[pyoperators] 01/01: Imported Upstream version 0.13.10

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Sat Dec 19 12:51:36 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch upstream
in repository pyoperators.

commit 7079071f0bbd0b752639d9129071a5203ade32f9
Author: Ghislain Antony Vaillant <ghisvail at gmail.com>
Date:   Sat Dec 19 12:29:39 2015 +0000

    Imported Upstream version 0.13.10
---
 PKG-INFO                          |   2 +-
 hooks.py                          | 185 ++++++++++++++++++++++++++++++++++----
 pyoperators/__init__.py           |  15 ++--
 pyoperators/core.py               |  11 +--
 pyoperators/fft.py                |  14 ++-
 pyoperators/iterative/optimize.py |  16 ++--
 pyoperators/linear.py             |   8 +-
 pyoperators/nonlinear.py          |   2 +-
 pyoperators/operators_pywt.py     |  46 ++++++----
 pyoperators/rules.py              |  18 ++--
 pyoperators/utils/misc.py         |  49 +++++-----
 setup.py                          |   2 +-
 test/test_broadcast.py            | 180 +++++++++++++++++++++++++++++++++++++
 test/test_zero.py                 |   4 +-
 14 files changed, 454 insertions(+), 98 deletions(-)

diff --git a/PKG-INFO b/PKG-INFO
index fad8aed..4df0926 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pyoperators
-Version: 0.13.6
+Version: 0.13.10
 Summary: Operators and solvers for high-performance computing.
 Home-page: http://pchanial.github.com/pyoperators
 Author: Pierre Chanial
diff --git a/hooks.py b/hooks.py
index 8b23583..0fd1794 100644
--- a/hooks.py
+++ b/hooks.py
@@ -30,6 +30,20 @@ configurable) or the last tag.
 
 # These variables can be changed by the hooks importer
 ABBREV = 5
+F77_OPENMP = True
+F90_OPENMP = True
+F77_COMPILE_ARGS_GFORTRAN = []
+F77_COMPILE_DEBUG_GFORTRAN = ['-fcheck=all -Og']
+F77_COMPILE_OPT_GFORTRAN = ['-Ofast -march=native']
+F90_COMPILE_ARGS_GFORTRAN = ['-cpp']
+F90_COMPILE_DEBUG_GFORTRAN = ['-fcheck=all -Og']
+F90_COMPILE_OPT_GFORTRAN = ['-Ofast -march=native']
+F77_COMPILE_ARGS_IFORT = []
+F77_COMPILE_DEBUG_IFORT = ['-check all']
+F77_COMPILE_OPT_IFORT = ['-fast']
+F90_COMPILE_ARGS_IFORT = ['-fpp -ftz -fp-model precise -ftrapuv -warn all']
+F90_COMPILE_DEBUG_IFORT = ['-check all']
+F90_COMPILE_OPT_IFORT = ['-fast']
 F2PY_TABLE = {'integer': {'int8': 'char',
                           'int16': 'short',
                           'int32': 'int',
@@ -38,6 +52,9 @@ F2PY_TABLE = {'integer': {'int8': 'char',
                        'real64': 'double'},
               'complex': {'real32': 'complex_float',
                           'real64': 'complex_double'}}
+FCOMPILERS_DEFAULT = 'ifort', 'gfortran'
+LIBRARY_OPENMP_GFORTRAN = 'gomp'
+LIBRARY_OPENMP_IFORT = 'iomp5'
 REGEX_RELEASE = '^v(?P<name>[0-9.]+)$'
 try:
     import os
@@ -52,10 +69,16 @@ import shutil
 import sys
 from distutils.command.clean import clean
 from numpy.distutils.command.build import build
+from numpy.distutils.command.build_clib import build_clib
+from numpy.distutils.command.build_ext import build_ext
 from numpy.distutils.command.build_src import build_src
 from numpy.distutils.command.sdist import sdist
 from numpy.distutils.core import Command
-from numpy.distutils.misc_util import has_f_sources
+from numpy.distutils.exec_command import find_executable
+from numpy.distutils.fcompiler import new_fcompiler
+from numpy.distutils.fcompiler.gnu import Gnu95FCompiler
+from numpy.distutils.fcompiler.intel import IntelEM64TFCompiler
+from numpy.distutils.misc_util import f90_ext_match, has_f_sources
 from subprocess import call, Popen, PIPE
 from warnings import filterwarnings
 
@@ -72,6 +95,24 @@ numpy.distutils.from_template.routine_start_re = re.compile(
 numpy.distutils.from_template.function_start_re = re.compile(
     r'\n     (\$|\*)\s*((im)?pure\s+|elemental\s+)*function\b', re.I)
 
+# monkey patch compilers
+Gnu95FCompiler.get_flags_debug = lambda self: []
+Gnu95FCompiler.get_flags_opt = lambda self: []
+IntelEM64TFCompiler.get_flags_debug = lambda self: []
+IntelEM64TFCompiler.get_flags_opt = lambda self: []
+
+# monkey patch the default Fortran compiler
+if sys.platform.startswith('linux'):
+    _id = 'linux.*'
+elif sys.platform.startswith('darwin'):
+    _id = 'darwin.*'
+else:
+    _id = None
+if _id is not None:
+    table = {'ifort': 'intelem', 'gfortran': 'gnu95'}
+    _df = (_id, tuple(table[f] for f in FCOMPILERS_DEFAULT)),
+    numpy.distutils.fcompiler._default_compilers = _df
+
 
 def get_cmdclass():
 
@@ -81,6 +122,114 @@ def get_cmdclass():
                            self.distribution.get_version())
             build.run(self)
 
+    class BuildClibCommand(build_clib):
+        def build_libraries(self, libraries):
+            if numpy.__version__ < "1.7":
+                fcompiler = self.fcompiler
+            else:
+                fcompiler = self._f_compiler
+            if isinstance(fcompiler,
+                          numpy.distutils.fcompiler.gnu.Gnu95FCompiler):
+                old_value = numpy.distutils.log.set_verbosity(-2)
+                exe = numpy.distutils.exec_command.find_executable('gcc-ar')
+                if exe is None:
+                    exe = numpy.distutils.exec_command.find_executable('ar')
+                numpy.distutils.log.set_verbosity(old_value)
+                self.compiler.archiver[0] = exe
+                flags = F77_COMPILE_ARGS_GFORTRAN + F77_COMPILE_OPT_GFORTRAN
+                if self.debug:
+                    flags += F77_COMPILE_DEBUG_GFORTRAN
+                if F77_OPENMP:
+                    flags += ['-openmp']
+                fcompiler.executables['compiler_f77'] += flags
+                flags = F90_COMPILE_ARGS_GFORTRAN + F90_COMPILE_OPT_GFORTRAN
+                if self.debug:
+                    flags += F90_COMPILE_DEBUG_GFORTRAN
+                if F90_OPENMP:
+                    flags += ['-openmp']
+                fcompiler.executables['compiler_f90'] += flags
+                fcompiler.libraries += [LIBRARY_OPENMP_GFORTRAN]
+            elif isinstance(fcompiler,
+                            numpy.distutils.fcompiler.intel.IntelFCompiler):
+                old_value = numpy.distutils.log.set_verbosity(-2)
+                self.compiler.archiver[0] = numpy.distutils.exec_command.find_executable('xiar')
+                numpy.distutils.log.set_verbosity(old_value)
+                flags = F77_COMPILE_ARGS_IFORT + F77_COMPILE_OPT_IFORT
+                if self.debug:
+                    flags += F77_COMPILE_DEBUG_IFORT
+                if F77_OPENMP:
+                    flags += ['-openmp']
+                fcompiler.executables['compiler_f77'] += flags
+                flags = F90_COMPILE_ARGS_IFORT + F90_COMPILE_OPT_IFORT
+                if self.debug:
+                    flags += F90_COMPILE_DEBUG_IFORT
+                if F90_OPENMP:
+                    flags += ['-openmp']
+                fcompiler.executables['compiler_f90'] += flags
+                fcompiler.libraries += [LIBRARY_OPENMP_IFORT]
+            else:
+                raise RuntimeError()
+            build_clib.build_libraries(self, libraries)
+
+    class BuildExtCommand(build_ext):
+        def build_extensions(self):
+            # Numpy bug: if an extension has a library only consisting of f77
+            # files, the extension language will always be f77 and no f90
+            # compiler will be initialized
+            need_f90_compiler = self._f90_compiler is None and \
+                any(any(f90_ext_match(s) for s in _.sources)
+                    for _ in self.extensions)
+            if need_f90_compiler:
+                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:
+                    fcompiler.customize(self.distribution)
+                if fcompiler and fcompiler.get_version():
+                    fcompiler.customize_cmd(self)
+                    fcompiler.show_customization()
+                else:
+                    ctype = fcompiler.compiler_type if fcompiler \
+                        else self.fcompiler
+                    self.warn('f90_compiler=%s is not available.' % ctype)
+
+            for fc in self._f77_compiler, self._f90_compiler:
+                if isinstance(fc,
+                              numpy.distutils.fcompiler.gnu.Gnu95FCompiler):
+                    flags = F77_COMPILE_ARGS_GFORTRAN + F77_COMPILE_OPT_GFORTRAN
+                    if self.debug:
+                        flags += F77_COMPILE_DEBUG_GFORTRAN
+                    if F77_OPENMP:
+                        flags += ['-openmp']
+                    fc.executables['compiler_f77'] += flags
+                    flags = F90_COMPILE_ARGS_GFORTRAN + F90_COMPILE_OPT_GFORTRAN
+                    if self.debug:
+                        flags += F90_COMPILE_DEBUG_GFORTRAN
+                    if F90_OPENMP:
+                        flags += ['-openmp']
+                    fc.executables['compiler_f90'] += flags
+                    fc.libraries += [LIBRARY_OPENMP_GFORTRAN]
+                elif isinstance(fc,
+                                numpy.distutils.fcompiler.intel.IntelFCompiler):
+                    flags = F77_COMPILE_ARGS_IFORT + F77_COMPILE_OPT_IFORT
+                    if self.debug:
+                        flags += F77_COMPILE_DEBUG_IFORT
+                    if F77_OPENMP:
+                        flags += ['-openmp']
+                    fc.executables['compiler_f77'] += flags
+                    flags = F90_COMPILE_ARGS_IFORT + F90_COMPILE_OPT_IFORT
+                    if self.debug:
+                        flags += F90_COMPILE_DEBUG_IFORT
+                    if F90_OPENMP:
+                        flags += ['-openmp']
+                    fc.executables['compiler_f90'] += flags
+                    fc.libraries += [LIBRARY_OPENMP_IFORT]
+            build_ext.build_extensions(self)
+
     class BuildSrcCommand(build_src):
         def initialize_options(self):
             build_src.initialize_options(self)
@@ -126,11 +275,9 @@ def get_cmdclass():
     class CleanCommand(clean):
         def run(self):
             clean.run(self)
-            try:
+            if is_git_tree():
                 print(run_git('clean -fdX' + ('n' if self.dry_run else '')))
                 return
-            except RuntimeError:
-                pass
 
             extensions = '.o', '.pyc', 'pyd', 'pyo', '.so'
             for root_, dirs, files in os.walk(root):
@@ -140,12 +287,6 @@ def get_cmdclass():
                 for d in dirs:
                     if d in ('build', '__pycache__'):
                         self.__delete(os.path.join(root_, d), dir=True)
-            files = (
-                'MANIFEST',
-                os.path.join(self.distribution.get_name(), '__init__.py'))
-            for f in files:
-                if os.path.exists(f):
-                    self.__delete(f)
 
         def __delete(self, file_, dir=False):
             msg = 'would remove' if self.dry_run else 'removing'
@@ -197,6 +338,8 @@ def get_cmdclass():
             pass
 
     return {'build': BuildCommand,
+            'build_clib': BuildClibCommand,
+            'build_ext': BuildExtCommand,
             'build_src': BuildSrcCommand,
             'clean': CleanCommand,
             'coverage': CoverageCommand,
@@ -219,11 +362,15 @@ def run_git(cmd, cwd=root):
         if stderr != '':
             stderr = '\n' + stderr.decode('utf-8')
         raise RuntimeError(
-            'Command failed (error {}): {}{}'.format(
+            'Command failed (error {0}): {1}{2}'.format(
                 process.returncode, cmd, stderr))
     return stdout.strip().decode('utf-8')
 
 
+def is_git_tree():
+    return os.path.exists(os.path.join(root, '.git'))
+
+
 def _get_version_git(default):
     INF = 2147483647
 
@@ -241,10 +388,11 @@ def _get_version_git(default):
     def get_description():
         branch = get_branch_name()
         try:
-            description = run_git('describe --abbrev={} --tags'.format(ABBREV))
+            description = run_git(
+                'describe --abbrev={0} --tags'.format(ABBREV))
         except RuntimeError:
             description = run_git(
-                'describe --abbrev={} --always'.format(ABBREV))
+                'describe --abbrev={0} --always'.format(ABBREV))
             regex = r"""^
             (?P<commit>.*?)
             (?P<dirty>(-dirty)?)
@@ -277,7 +425,8 @@ def _get_version_git(default):
             common = run_git('merge-base HEAD ' + branch)
         except RuntimeError:
             return INF  # no common ancestor, the branch is dangling
-        return int(run_git('rev-list --count HEAD ^' + common))
+        # git 1.8: return int(run_git('rev-list --count HEAD ^' + common))
+        return len(run_git('rev-list HEAD ^' + common).split('\n'))
 
     def get_rev_since_any_branch():
         if REGEX_RELEASE.startswith('^'):
@@ -297,9 +446,7 @@ def _get_version_git(default):
         # no branch has been created from an ancestor
         return INF
 
-    try:
-        run_git('rev-parse --is-inside-work-tree')
-    except (OSError, RuntimeError):
+    if not is_git_tree():
         return ''
 
     branch, tag, rev_tag, commit, dirty = get_description()
@@ -331,7 +478,7 @@ def _get_version_git(default):
 
     if rev_branch == rev_tag == INF:
         # no branch and no tag from ancestors, counting from root
-        rev = int(run_git('rev-list --count HEAD'))
+        rev = len(run_git('rev-list HEAD').split('\n'))
         if branch != 'master':
             suffix = 'rev'
     elif rev_tag <= rev_branch:
@@ -346,7 +493,7 @@ def _get_version_git(default):
             suffix = 'pre'
     if name != '':
         name += '.'
-    return '{}{}{:02}{}'.format(name, suffix, rev, dirty)
+    return '{0}{1}{2:02}{3}'.format(name, suffix, rev, dirty)
 
 
 def _get_version_init_file(name):
diff --git a/pyoperators/__init__.py b/pyoperators/__init__.py
index f74350b..bf886a4 100644
--- a/pyoperators/__init__.py
+++ b/pyoperators/__init__.py
@@ -10,7 +10,6 @@ The PyOperators package contains the following modules or packages:
 - operators_pywt : (optional) loaded if PyWavelets is present.
 
 """
-
 from .utils import *
 from .utils.mpi import MPI
 from .core import *
@@ -18,19 +17,19 @@ from .fft import *
 from .linear import *
 from .nonlinear import *
 from .operators_mpi import *
+try:
+    import pywt
+    from .operators_pywt import *
+except ImportError:
+    pass
 from .proxy import *
 from . import iterative
 from .iterative import pcg
 from .rules import rule_manager
 from .warnings import PyOperatorsWarning
-
-try:
-    from .operators_pywt import *
-except(ImportError):
-    pass
-
 import sys
 import types
+
 __all__ = [f for f in dir() if f[0] != '_' and not isinstance(eval(f),
            types.ModuleType)]
 
@@ -43,4 +42,4 @@ I = IdentityOperator()
 O = ZeroOperator()
 X = Variable('X')
 
-__version__ = u'0.13.6'
+__version__ = u'0.13.10'
diff --git a/pyoperators/core.py b/pyoperators/core.py
index 4525704..e168526 100644
--- a/pyoperators/core.py
+++ b/pyoperators/core.py
@@ -100,7 +100,7 @@ class Operator(object):
         and input dtypes. If dtype is None, the output dtype is the input
         dtype.
     C : Operator
-        Oonjugate operator.
+        Conjugate operator.
     T : Operator
         Tranpose operator.
     H : Operator
@@ -1528,7 +1528,7 @@ class CompositeOperator(Operator):
 
     def _validate_operands(self, operands, constant=False):
         if not isinstance(operands, (list, tuple, types.GeneratorType)):
-            operands = [operands]
+            raise TypeError('The expected input is a sequence of operators.')
         return [asoperator(op, constant=constant) for op in operands]
 
     def _validate_comm(self, operands):
@@ -1835,7 +1835,7 @@ class BlockSliceOperator(CommutativeCompositeOperator):
 
     Examples
     --------
-    >>> op = BlockSliceOperator(HomothetyOperator(3), slice(None,None,2))
+    >>> op = BlockSliceOperator([HomothetyOperator(3)], slice(None,None,2))
     >>> op(np.ones(6))
     array([ 3.,  1.,  3.,  1.,  3.,  1.])
 
@@ -3335,7 +3335,8 @@ class BlockRowOperator(BlockOperator):
             keywords.get('flags', {}), linear=operation is operator.iadd)
         BlockOperator.__init__(self, operands, partitionin=partitionin, axisin=
                                axisin, new_axisin=new_axisin, **keywords)
-
+        if not isinstance(self, BlockRowOperator):
+            return
         self.operation = operation
         self._need_temporary = any(not o.flags.update_output for o in
                                    self.operands[1:])
@@ -3532,7 +3533,7 @@ class BroadcastingBase(Operator):
                     return
         else:
             if b == 'rightward':
-                if axis_ >= ndim:
+                if axis_ > ndim:
                     do_replicate = True
             else:
                 if axis is not None:
diff --git a/pyoperators/fft.py b/pyoperators/fft.py
index a22a647..358d53e 100644
--- a/pyoperators/fft.py
+++ b/pyoperators/fft.py
@@ -15,8 +15,6 @@ from .utils import (complex_dtype, isalias, omp_num_threads, product,
 from .utils.ufuncs import multiply_conjugate
 from .warnings import warn, PyOperatorsWarning
 
-__all__ = ['ConvolutionOperator', 'FFTOperator']
-
 try:
     import pyfftw
     FFTW_DEFAULT_NUM_THREADS = omp_num_threads()
@@ -27,6 +25,18 @@ try:
 except:
     warn('The pyFFTW library is not installed.', PyOperatorsWarning)
 
+__all__ = ['ConvolutionOperator', 'FFTOperator']
+
+
+# doctest nose fixture
+def setup_module(module):
+    try:
+        import pyfftw
+    except ImportError:
+        from nose.plugins.skip import SkipTest
+        raise SkipTest()
+
+
 # FFTW out-of-place transforms:
 # PRESERVE_INPUT: default except c2r and hc2r
 # DESTROY_INPUT: default for c2r and hc2r, only possibility for multi c2r
diff --git a/pyoperators/iterative/optimize.py b/pyoperators/iterative/optimize.py
index 51fae5a..02c36a9 100644
--- a/pyoperators/iterative/optimize.py
+++ b/pyoperators/iterative/optimize.py
@@ -60,7 +60,7 @@ class FminWrapper(object):
 
 
 class FminCOBYLA(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_cobyla.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_cobyla.__doc__
 
     def __init__(self, criterion, cons, x0=None, *args, **kwargs):
         self.cons = cons
@@ -82,7 +82,7 @@ class FminCOBYLA(FminWrapper):
 
 
 class FminPowell(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_powell.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_powell.__doc__
 
     def __call__(self):
         self.first_guess()
@@ -99,7 +99,7 @@ class FminPowell(FminWrapper):
 
 
 class FminCG(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_cg.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_cg.__doc__
 
     def __call__(self):
         self.first_guess()
@@ -117,7 +117,7 @@ class FminCG(FminWrapper):
 
 
 class FminTNC(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_tnc.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_tnc.__doc__
 
     def __call__(self):
         self.first_guess()
@@ -135,7 +135,7 @@ class FminTNC(FminWrapper):
 
 
 class FminNCG(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_ncg.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_ncg.__doc__
 
     def __init__(self, criterion, x0=None, *args, **kwargs):
         super(FminNCG, self).__init__(criterion, x0=x0, *args, **kwargs)
@@ -160,7 +160,7 @@ class FminNCG(FminWrapper):
 
 
 class FminLBFGSB(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_l_bfgs_b.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_l_bfgs_b.__doc__
 
     def __call__(self):
         self.first_guess()
@@ -178,7 +178,7 @@ class FminLBFGSB(FminWrapper):
 
 
 class FminSLSQP(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_slsqp.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_slsqp.__doc__
 
     def __call__(self):
         self.first_guess()
@@ -197,7 +197,7 @@ class FminSLSQP(FminWrapper):
 
 
 class FminBFGS(FminWrapper):
-    __doc__ = FminWrapper.__doc__ + opt.fmin_bfgs.__doc__
+#    __doc__ = FminWrapper.__doc__ + opt.fmin_bfgs.__doc__
 
     def __call__(self):
         self.first_guess()
diff --git a/pyoperators/linear.py b/pyoperators/linear.py
index cf57824..9e6e9af 100644
--- a/pyoperators/linear.py
+++ b/pyoperators/linear.py
@@ -754,7 +754,6 @@ class Rotation2dOperator(DenseBlockDiagonalOperator):
     Example
     -------
     >>> r = Rotation2dOperator([45, 90], degrees=True)
-    >>> r([1, 0])
     >>> print(r([1, 0]))
     [[  7.07106781e-01   7.07106781e-01]
      [  6.12323400e-17   1.00000000e+00]]
@@ -821,7 +820,7 @@ class Rotation3dOperator(DenseBlockDiagonalOperator):
     [  6.12323400e-17   0.00000000e+00  -1.00000000e+00]
     >>> r2 = Rotation3dOperator("XYZ", 30, 40, 50, degrees=True)
     >>> print(r2([1, 0, 0]))
-    [ 0.49240388  0.58682409 -0.64278761]d
+    [ 0.49240388  0.58682409 -0.64278761]
     >>> r3 = Rotation3dOperator("ZY'X''", 50, 40, 30, degrees=True)
     >>> print(r3([1, 0, 0]))
     [ 0.49240388  0.58682409 -0.64278761]
@@ -1046,9 +1045,8 @@ class TridiagonalOperator(Operator):
 
         Exemple
         -------
-        >>> import operators
-        >>> T = operators.TridiagonalOperator([1, 2, 3], [4, 5], [6, 7])
-        >>> T.todense()
+        >>> tri = TridiagonalOperator([1, 2, 3], [4, 5], [6, 7])
+        >>> tri.todense()
         array([[1, 6, 0],
                [4, 2, 7],
                [0, 5, 3]])
diff --git a/pyoperators/nonlinear.py b/pyoperators/nonlinear.py
index a695c57..9ab36bd 100644
--- a/pyoperators/nonlinear.py
+++ b/pyoperators/nonlinear.py
@@ -617,7 +617,7 @@ class NumexprOperator(Operator):
     -------
     >>> k = 1.2
     >>> op = NumexprOperator('exp(input+k)', {'k':k})
-    >>> print op(1) == np.exp(2.2)
+    >>> print(op(1) == np.exp(2.2))
     True
 
     """
diff --git a/pyoperators/operators_pywt.py b/pyoperators/operators_pywt.py
index a33b960..d00458d 100644
--- a/pyoperators/operators_pywt.py
+++ b/pyoperators/operators_pywt.py
@@ -4,29 +4,41 @@ For now only 1D and 2D wavelets are available.
 
 """
 from __future__ import absolute_import, division, print_function
-import numpy as np
-import pywt
 from .core import Operator, CompositionOperator
 from .flags import linear, real
+import numpy as np
+try:
+    import pywt
+    # dict of corresponding wavelets
+    rwavelist = {}
+    for l in pywt.wavelist():
+        if 'bior' in l:
+            rwavelist[l] = 'rbio' + l[-3:]
+        elif 'rbio' in l:
+            rwavelist[l] = 'bior' + l[-3:]
+        else:
+            rwavelist[l] = l
+except ImportError:
+    pass
 
 __all__ = ['WaveletOperator', 'Wavelet2dOperator']
 
-# dict of corresponding wavelets
-rwavelist = {}
-for l in pywt.wavelist():
-    if 'bior' in l:
-        rwavelist[l] = 'rbio' + l[-3:]
-    elif 'rbio' in l:
-        rwavelist[l] = 'bior' + l[-3:]
-    else:
-        rwavelist[l] = l
+
+# doctest nose fixture
+def setup_module(module):
+    try:
+        import pywt
+    except ImportError:
+        from nose.plugins.skip import SkipTest
+        raise SkipTest()
 
 
 @real
 @linear
 class WaveletOperator(Operator):
+    skip_doctest = True
     def __init__(self, wavelet, mode='zpd', level=None, shapein=None,
-                 **keywords):
+                 dtype=float, **keywords):
         """
         1D wavelet decomposition and reconstruction. Wavelet coefficients
         are stored in a vector (ndarray with ndim=1).
@@ -35,7 +47,6 @@ class WaveletOperator(Operator):
         --------
         >>> W = WaveletOperator("haar", level=1, shapein=2)
         >>> W.todense()
-
         array([[ 0.70710678,  0.70710678],
                [ 0.70710678, -0.70710678]])
 
@@ -63,7 +74,8 @@ class WaveletOperator(Operator):
         self.cumsizes = np.zeros(len(self.sizes) + 1)
         np.cumsum(self.sizes, out=self.cumsizes[1:])
         shapeout = sum(self.sizes)
-        Operator.__init__(self, shapein=shapein, shapeout=shapeout, **keywords)
+        Operator.__init__(self, shapein=shapein, shapeout=shapeout,
+                          dtype=dtype, **keywords)
         if self.wavelet.orthogonal:
             self.set_rule('T,.', '1', CompositionOperator)
 
@@ -89,7 +101,7 @@ class WaveletOperator(Operator):
 @linear
 class Wavelet2dOperator(Operator):
     def __init__(self, wavelet, mode='zpd', level=None, shapein=None,
-                 **keywords):
+                 dtype=float, **keywords):
         """
         2D wavelet decomposition and reconstruction. Wavelet coefficients
         are stored in a vector (ndarray with ndim=1).
@@ -98,7 +110,6 @@ class Wavelet2dOperator(Operator):
         -------
         >>> W = Wavelet2dOperator("haar", level=1, shapein=(2, 2))
         >>> W.todense()
-
         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],
@@ -133,7 +144,8 @@ class Wavelet2dOperator(Operator):
         np.cumsum(self.sizes, out=self.cumsizes[1:])
         shapeout = sum(self.sizes)
 
-        Operator.__init__(self, shapein=shapein, shapeout=shapeout, **keywords)
+        Operator.__init__(self, shapein=shapein, shapeout=shapeout,
+                          dtype=dtype, **keywords)
         if self.wavelet.orthogonal:
             self.set_rule('T,.', '1', CompositionOperator)
 
diff --git a/pyoperators/rules.py b/pyoperators/rules.py
index 703e4ae..7fb007a 100644
--- a/pyoperators/rules.py
+++ b/pyoperators/rules.py
@@ -265,28 +265,32 @@ class RuleManager(object):
     Examples
     --------
     To prevent rule simplifications:
-    >>> from pyoperators.rules import rules
-    >>> rules['none'] = True
+    >>> from pyoperators.rules import rule_manager
+    >>> rule_manager['none'] = True
+
+    To re-enable rule simplifications:
+    >>> rule_manager['none'] = False
+
     or:
-    >>> with rules(none=True):
-    ...     print(rules['none'])
+    >>> with rule_manager(none=True):
     ...     # in this context, operator simplification rules are inhibited
-    >>> print(rules['none'])
+    ...     print(rule_manager['none'])
     True
+    >>> print(rule_manager['none'])
     False
 
     It is possible to nest contexts:
     >>> print(rule_manager['none'])
+    False
     >>> with rule_manager(none=True) as new_rule_manager:
     ...     print(rule_manager['none'])
     ...     with new_rule_manager(none=False):
     ...         print(rule_manager['none'])
     ...     print(rule_manager['none'])
-    >>> print(rule_manager['none'])
-    False
     True
     False
     True
+    >>> print(rule_manager['none'])
     False
 
     """
diff --git a/pyoperators/utils/misc.py b/pyoperators/utils/misc.py
index 1bfaee1..30c3c1e 100644
--- a/pyoperators/utils/misc.py
+++ b/pyoperators/utils/misc.py
@@ -85,12 +85,15 @@ def deprecated(msg):
     Example
     -------
     >>> @deprecated('use mynewfunc instead.')
-    >>> def myfunc():
+    ... def myfunc():
     ...    pass
 
-    >>>@deprecated
-    >>>class MyClass(MyNewClass):
-    >>>    pass
+    >>> class MyNewClass(object):
+    ...     # here goes the new class to be used instead of the deprecated one
+    ...     pass
+    >>> @deprecated
+    ... class MyClass(MyNewClass):
+    ...    pass
 
     """
     def decorator(x):
@@ -572,9 +575,9 @@ def inspect_special_values(x):
     Examples
     --------
     >>> inspect_special_values([0,-1,-1])
-    2, 1, 0, False, False
+    (2, 1, 0, False, False)
     >>> inspect_special_values([0,-1,-1,1.2])
-    0, 0, 0, True, False
+    (0, 0, 0, True, False)
 
     """
     x = np.asarray(x)
@@ -655,7 +658,7 @@ def last(l, f):
 
     Example:
     --------
-    >>> first([1.,2.,3.], lambda x: x > 1.5)
+    >>> last([1.,2.,3.], lambda x: x > 1.5)
     3.0
 
     """
@@ -731,7 +734,7 @@ def merge_none(a, b):
     Example
     -------
     >>> merge_none([1,None,3],[None,2,3])
-    [1, 2, 3]
+    (1, 2, 3)
     """
     if a is b is None:
         return None
@@ -851,7 +854,7 @@ def reshape_broadcast(x, shape):
     [[[0 0]
       [1 1]
       [2 2]]
-
+    <BLANKLINE>
      [[0 0]
       [1 1]
       [2 2]]]
@@ -946,8 +949,8 @@ def strelapsed(t0, msg='Elapsed time'):
     >>> import time
     >>> t0 = time.time()
     >>> pass
-    >>> print(strelapsed(t0, 'Did nothing in'))
-    Info computernode: Did nothing in... 0.00s
+    >>> strelapsed(t0, 'Did nothing in')  # doctest: +ELLIPSIS
+    'Info ...: Did nothing in... 0.00s'
 
     """
     import time
@@ -989,8 +992,8 @@ def strinfo(msg):
         The information message.
     Example
     -------
-    >>> print(strinfo('My information message'))
-    Info computernode: My information message.
+    >>> strinfo('My information message')  # doctest: +ELLIPSIS
+    'Info ...: My information message.'
 
     """
     from .mpi import MPI
@@ -1016,8 +1019,8 @@ def strnbytes(nbytes):
     Example
     -------
     >>> a = np.empty((100,100))
-    >>> print(strnbytes(a.nbytes))
-    78.125 KiB
+    >>> strnbytes(a.nbytes)
+    '78.125 KiB'
 
     """
     if nbytes < 1024:
@@ -1053,7 +1056,7 @@ def strplural(n, name, nonumber=False, s=''):
     '1 cat'
     >>> strplural(2, 'cat')
     '2 cats'
-    >>> strplural(2, 'cat', prepend=False)
+    >>> strplural(2, 'cat', nonumber=True)
     'cats'
     >>> animals = ['cat', 'dog']
     >>> strplural(len(animals), 'animal', s=': ') + ', '.join(animals)
@@ -1096,26 +1099,26 @@ class Timer(object):
     Examples
     --------
     >>> import time
-    >>> with Timer('Elapsed time: '):
+    >>> with Timer('Elapsed time: '):  # doctest: +SKIP
     ...     time.sleep(0.1)
     Elapsed time: 0.100191831589s
 
-    >>> with Timer() as t:
+    >>> with Timer() as t:  # doctest: +SKIP
     ...     time.sleep(0.1)
     ...     print(t.elapsed)
     ...     time.sleep(0.1)
-    ... print(t.elapsed)
     0.100234985352
+    >>> print(t.elapsed)  # doctest: +SKIP
     0.200633049011
 
     >>> t = Timer(cumulative=True)
     >>> with t:
     ...     time.sleep(0.1)
-    >>> print(t.elapsed)
-    >>> with t:
-    ...     time.sleep(0.1)
-    >>> print(t.elapsed)
+    >>> print(t.elapsed)  # doctest: +SKIP
     0.100238084793
+    >>> with t:
+    ...     time.sleep(0.1)  # doctest: +SKIP
+    >>> print(t.elapsed)  # doctest: +SKIP
     0.200490236282
 
     """
diff --git a/setup.py b/setup.py
index 5b60b0a..6367a2e 100644
--- a/setup.py
+++ b/setup.py
@@ -11,7 +11,7 @@ name = 'pyoperators'
 long_description = open('README.rst').read()
 keywords = 'scientific computing'
 platforms = 'MacOS X,Linux,Solaris,Unix,Windows'
-define_macros = [] if sys.version_info.major == 2 else [('NPY_PY3K', None)]
+define_macros = [] if sys.version_info[0] == 2 else [('NPY_PY3K', None)]
 
 ext_modules = [Extension("pyoperators.utils.cythonutils",
                          sources=["pyoperators/utils/cythonutils.pyx"],
diff --git a/test/test_broadcast.py b/test/test_broadcast.py
new file mode 100644
index 0000000..427f91e
--- /dev/null
+++ b/test/test_broadcast.py
@@ -0,0 +1,180 @@
+from numpy.testing import assert_equal
+from pyoperators import Operator, operation_assignment
+from pyoperators.core import _pool
+from pyoperators.utils.testing import assert_same
+from pyoperators.flags import handle_broadcast
+import numpy as np
+
+
+data = np.array([[0, 1], [1, 2], [2, 3]])
+m = data.shape[0]
+n = data.shape[1]
+
+
+class MyOperator(Operator):
+    def direct(self, input, output):
+        np.dot(data, input, out=output)
+
+
+class ExplExpl(MyOperator):
+    def __init__(self, **keywords):
+        MyOperator.__init__(self, shapein=n, shapeout=m, **keywords)
+
+
+ at handle_broadcast('leftward')
+class ExplExplLeft(ExplExpl):
+    pass
+
+
+ at handle_broadcast('rightward')
+class ExplExplRight(ExplExpl):
+    def direct(self, input, output):
+        np.dot(data, input.T, out=output.T)
+
+
+class ExplUnco(MyOperator):
+    def __init__(self, **keywords):
+        MyOperator.__init__(self, shapeout=m, naxesin=1, **keywords)
+
+
+ at handle_broadcast('leftward')
+class ExplUncoLeft(ExplUnco):
+    pass
+
+
+ at handle_broadcast('rightward')
+class ExplUncoRight(ExplUnco):
+    def direct(self, input, output):
+        np.dot(data, input.T, out=output.T)
+
+
+class UncoExpl(MyOperator):
+    def __init__(self, **keywords):
+        MyOperator.__init__(self, shapein=n, naxesout=1, **keywords)
+
+
+ at handle_broadcast('leftward')
+class UncoExplLeft(UncoExpl):
+    pass
+
+
+ at handle_broadcast('rightward')
+class UncoExplRight(UncoExpl):
+    def direct(self, input, output):
+        np.dot(data, input.T, out=output.T)
+
+
+class ImplImpl(MyOperator):
+    def __init__(self, **keywords):
+        MyOperator.__init__(self, naxesin=1, naxesout=1, **keywords)
+
+    def reshapein(self, shape):
+        return (m,)
+
+    def reshapeout(self, shape):
+        return (n,)
+
+
+ at handle_broadcast('leftward')
+class ImplImplLeft(ImplImpl):
+    pass
+
+
+ at handle_broadcast('rightward')
+class ImplImplRight(ImplImpl):
+    def direct(self, input, output):
+        np.dot(data, input.T, out=output.T)
+
+
+class ImplUnco(MyOperator):
+    def __init__(self, **keywords):
+        MyOperator.__init__(self, naxesin=1, naxesout=1, **keywords)
+
+    def reshapein(self, shape):
+        return (m,)
+
+
+ at handle_broadcast('leftward')
+class ImplUncoLeft(ImplUnco):
+    pass
+
+
+ at handle_broadcast('rightward')
+class ImplUncoRight(ImplUnco):
+    def direct(self, input, output):
+        np.dot(data, input.T, out=output.T)
+
+
+class UncoImpl(MyOperator):
+    def __init__(self, **keywords):
+        MyOperator.__init__(self, naxesin=1, naxesout=1, **keywords)
+
+    def reshapeout(self, shape):
+        return (n,)
+
+
+ at handle_broadcast('leftward')
+class UncoImplLeft(UncoImpl):
+    pass
+
+
+ at handle_broadcast('rightward')
+class UncoImplRight(UncoImpl):
+    def direct(self, input, output):
+        np.dot(data, input.T, out=output.T)
+
+
+def repeat_iter(iterable, n=1):
+    for _ in iterable:
+        for i in xrange(n):
+            yield _
+
+
+cls = (ExplExpl, ExplExplLeft, ExplExplRight,
+       ExplUnco, ExplUncoLeft, ExplUncoRight,
+       UncoExpl, UncoExplLeft, UncoExplRight,
+       ImplImpl, ImplImplLeft, ImplImplRight,
+       ImplUnco, ImplUncoLeft, ImplUncoRight,
+       UncoImpl, UncoImplLeft, UncoImplRight)
+
+
+def test_nobroadcast():
+    def func(cls, k, b):
+        op = cls(broadcast=b)
+        assert_equal(cls.__name__[:8].lower(),
+                     op.flags.shape_output[:4] + op.flags.shape_input[:4])
+        assert_same(op.todense(**k), data)
+    keywords = repeat_iter(({},
+                            {'shapein': n},
+                            {'shapeout': m},
+                            {'shapein': n},
+                            {'shapein': n},
+                            {'shapeout': m}), n=3)
+    for cls_, keywords_ in zip(cls, keywords):
+        for b in 'leftward', 'rightward':
+            yield func, cls_, keywords_, b
+
+
+def test_broadcast():
+    def p(s, k):
+        if broadcast == 'leftward':
+            return s + (k,)
+        return (k,) + s
+
+    def func(bshape, broadcast, cls, keywords):
+        op = cls(broadcast=broadcast)
+        if broadcast == 'leftward':
+            dense = np.kron(np.eye(np.product(bshape)), data)
+        else:
+            dense = np.kron(data, np.eye(np.product(bshape)))
+        assert_same(op.todense(**keywords), dense)
+    for bshape in (1,), (2,), (2, 1), (1, 2), (2, 3):
+        for broadcast in 'leftward', 'rightward':
+            keywords = repeat_iter(({'shapein': p(bshape, n)},
+                                    {'shapein': p(bshape, n)},
+                                    {'shapeout': p(bshape, m)},
+                                    {'shapein': p(bshape, n)},
+                                    {'shapein': p(bshape, n)},
+                                    {'shapeout': p(bshape, m)}), n=3)
+            for cls_, keywords_ in zip(cls, keywords):
+                yield func, bshape, broadcast, cls_, keywords_
diff --git a/test/test_zero.py b/test/test_zero.py
index ef40842..877b8bf 100644
--- a/test/test_zero.py
+++ b/test/test_zero.py
@@ -6,7 +6,8 @@ from pyoperators import (
     rule_manager, O)
 from pyoperators.utils import ndarraywrap
 from pyoperators.utils.testing import (
-    assert_is, assert_is_instance, assert_is_none, assert_same, assert_is_type)
+    assert_is, assert_is_instance, assert_is_none, assert_same, assert_is_type,
+    skiptest)
 from .common import OPS, ndarray2, attr2
 
 op = Operator()
@@ -68,6 +69,7 @@ def test_zero5():
     assert_equal(oz.shapeout, o.shapeout, 'oz, out')
 
 
+ at skiptest
 def test_zero6():
     @flags.linear
     class Op(Operator):

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pyoperators.git



More information about the debian-science-commits mailing list