# -*- coding: utf-8 -*-
from setuptools import setup

package_dir = \
{'': 'src'}

packages = \
['mmfutils',
 'mmfutils.math',
 'mmfutils.math.bases',
 'mmfutils.math.bases.tests',
 'mmfutils.math.integrate',
 'mmfutils.math.integrate.tests',
 'mmfutils.math.tests',
 'mmfutils.performance',
 'mmfutils.plot',
 'mmfutils.solve',
 'mmfutils.solve.tests',
 'mmfutils.tests']

package_data = \
{'': ['*']}

install_requires = \
['husl>=4.0.3,<4.1.0', 'zope.interface>=5.4.0,<5.5.0']

extras_require = \
{':python_version < "3.8"': ['importlib-metadata>=1.0,<2.0'],
 'doc': ['Sphinx>=3.5.4,<3.6.0',
         'mmf-setup>=0.3.1,<0.4.0',
         'mock>=4.0.3,<4.1.0',
         'nbconvert>=6.0.7,<6.1.0',
         'sphinx-rtd-theme>=0.5.2,<0.6.0'],
 'doc:python_version >= "3.6" and python_version < "4.0"': ['numpy',
                                                            'matplotlib'],
 'doc:python_version >= "3.7" and python_version < "4.0"': ['numpy>=1.20.2,<1.21.0',
                                                            'matplotlib>=3.4.1,<3.5.0'],
 'fftw': ['pyFFTW>=0.12.0,<0.13.0'],
 'test': ['ipyparallel>=6.3.0,<6.4.0',
          'numexpr>=2.7.3,<2.8.0',
          'persist>=3.0,<4.0',
          'psutil>=5.8.0,<5.9.0',
          'pyFFTW>=0.12.0,<0.13.0',
          'pytest>=6.2.3,<6.3.0',
          'pytest-cov>=2.11.1,<2.12.0',
          'uncertainties>=3.1.5,<3.2.0',
          'poetry>=1.1.12,<1.2.0'],
 'test:python_version < "3.10"': ['numba>=0.53.1,<0.54.0'],
 'test:python_version >= "3.6" and python_version < "4.0"': ['matplotlib',
                                                             'scipy'],
 'test:python_version >= "3.7" and python_version < "3.10"': ['scipy>=1.7.3,<1.8.0'],
 'test:python_version >= "3.7" and python_version < "4.0"': ['matplotlib>=3.4.1,<3.5.0']}

setup_kwargs = {
    'name': 'mmfutils',
    'version': '0.6.0',
    'description': 'Small set of utilities: containers and interfaces.',
    'long_description': 'MMF Utils\n=========\n\nSmall set of utilities: containers and interfaces.\n\nThis package provides some utilities that I tend to rely on during\ndevelopment. Presently it includes some convenience containers, plotting\ntools, and a patch for including\n`zope.interface <http://docs.zope.org/zope.interface/>`__ documentation\nin a notebook.\n\n(Note: If this file does not render properly, try viewing it through\n`nbviewer.org <http://nbviewer.ipython.org/urls/bitbucket.org/mforbes/mmfutils-fork/raw/tip/doc/README.ipynb>`__)\n\n**Documentation:** http://mmfutils.readthedocs.org\n\n**Source:**\n\n-  https://alum.mit.edu/www/mforbes/hg/forbes-group/mmfutils: Permalink\n   (will forward).\n-  https://hg.iscimath.org/forbes-group/mmfutils: Current, in case the\n   permalink fails.\n-  https://github.com/forbes-group/mmfutils: Public read-only mirror.\n\n**Issues:**\nhttps://alum.mit.edu/www/mforbes/hg/forbes-group/mmfutils/issues\n\n**Build Status**\n\n|Documentation Status| |Build Status|\n\n.. |Documentation Status| image:: https://readthedocs.org/projects/mmfutils/badge/?version=latest\n   :target: https://mmfutils.readthedocs.io/en/latest/?badge=latest\n.. |Build Status| image:: https://cloud.drone.io/api/badges/forbes-group/mmfutils/status.svg\n   :target: https://cloud.drone.io/forbes-group/mmfutils\n\nInstalling\n----------\n\nThis package can be installed from\n`PyPI <https://pypi.org/project/mmfutils/>`__:\n\n.. code:: bash\n\n   python3 -m pip install mmfutils\n\nor, if you need to install from source, you can get it from one of the\nrepositories:\n\n.. code:: bash\n\n   python3 -m pip install hg+https://alum.mit.edu/www/mforbes/hg/forbes-group/mmfutils\n   python3 -m pip install git+https://github.com/forbes-group/mmfutils\n\nUsage\n=====\n\nContainers\n----------\n\nObjectBase and Object\n~~~~~~~~~~~~~~~~~~~~~\n\nThe ``ObjectBase`` and ``Object`` classes provide some useful features\ndescribed below. Consider a problem where a class is defined through a\nfew parameters, but requires extensive initialization before it can be\nproperly used. An example is a numerical simulation where one passes the\nnumber of grid points :math:`N` and a length :math:`L`, but the\ninitialization must generate large grids for efficient use later on.\nThese grids should be generated before computations begin, but should\nnot be re-generated every time needed. They also should not be pickled\nwhen saved to disk.\n\n**Deferred initialization via the ``init()`` method:** The idea here\nchanges the semantics of ``__init__()`` slightly by deferring any\nexpensive initialization to ``init()``. Under this scheme,\n``__init__()`` should only set and check what we call picklable\nattributes: these are parameters that define the object (they will be\npickled in ``Object`` below) and will be stored in a list\n``self.picklable_attributes`` which is computed at the end of\n``ObjectBase.__init__()`` as the list of all keys in ``__dict__``. Then,\n``ObjectBase.__init__()`` will call ``init()`` where all remaining\nattributes should be calculated.\n\nThis allows users to change various attributes, then reinitialize the\nobject once with an explicit call to ``init()`` before performing\nexpensive computations. This is an alternative to providing complete\nproperties (getters and setters) for objects that need to trigger\ncomputation. The use of setters is safer, but requires more work on the\nside of the developer and can lead to complex code when different\nproperties depend on each other. The approach here puts all computations\nin a single place. Of course, the user must remember to call ``init()``\nbefore working with the object.\n\nTo facilitate this, we provide a mild check in the form of an\n``initialized`` flag that is set to ``True`` at the end of the base\n``init()`` chain, and set to ``False`` if any variables are in\n``pickleable_attributes`` are set.\n\n**Serialization and Deferred Initialization:** The base class\n``ObjectBase`` does not provide any pickling services but does provide a\nnice representation. Additional functionality is provided by ``Object``\nwhich uses the features of ``ObjectBase`` to define ``__getstate__()``\nand ``__setstate__()`` methods for pickling which pickle only the\n``picklable_attributes``. Note: unpickling an object will **not** call\n``__init__()`` but will call ``init()`` giving objects a chance to\nrestore the computed attributes from pickles.\n\n-  **Note:** *Before using, consider if these features are really needed\n   – with all such added functionality comes additional potential\n   failure modes from side-interactions. The ``ObjectBase`` class is\n   quite simple, and therefore quite safe, while ``Object`` adds\n   additional functionality with potential side-effects. For example, a\n   side-effect of support for pickles is that ``copy.copy()`` will also\n   invoke ``init()`` when copying might instead be much faster. Thus, we\n   recommend only using ``ObjectBase`` for efficient code.*\n\nObject Example\n^^^^^^^^^^^^^^\n\n.. code:: ipython3\n\n    ROOTDIR = !hg root\n    ROOTDIR = ROOTDIR[0]\n    import sys;sys.path.insert(0, ROOTDIR)\n    \n    import numpy as np\n    \n    from mmfutils.containers import ObjectBase, ObjectMixin\n    \n    class State(ObjectBase):  \n        _quiet = False\n        def __init__(self, N, L=1.0, **kw):\n            """Set all of the picklable parameters, in this case, N and L."""\n            self.N = N\n            self.L = L\n            \n            # Now register these and call init()\n            super().__init__(**kw)\n            if not self._quiet:\n                print("__init__() called")\n            \n        def init(self):\n            """All additional initializations"""\n            if not self._quiet:\n                print("init() called")\n            dx = self.L / self.N\n            self.x = np.arange(self.N, dtype=float) * dx - self.L/2.0\n            self.k = 2*np.pi * np.fft.fftfreq(self.N, dx)\n    \n            # Set highest momentum to zero if N is even to\n            # avoid rapid oscillations\n            if self.N % 2 == 0:\n                self.k[self.N//2] = 0.0\n    \n            # Calls base class which sets self.initialized\n            super().init()\n                \n        def compute_derivative(self, f):\n            """Return the derivative of f."""        \n            return np.fft.ifft(self.k*1j*np.fft.fft(f)).real\n    \n    s = State(256)\n    print(s)  # No default value for L\n\n\n.. parsed-literal::\n\n    init() called\n    __init__() called\n    State(L=1.0, N=256)\n\n\n.. code:: ipython3\n\n    s.L = 2.0\n    print(s)\n\n\n.. parsed-literal::\n\n    State(L=2.0, N=256)\n\n\nOne feature is that a nice ``repr()`` of the object is produced. Now\nlet’s do a calculation:\n\n.. code:: ipython3\n\n    f = np.exp(3*np.cos(2*np.pi*s.x/s.L)) / 15\n    df = -2.*np.pi/5.*np.exp(3*np.cos(2*np.pi*s.x/s.L))*np.sin(2*np.pi*s.x/s.L)/s.L\n    np.allclose(s.compute_derivative(f), df)\n\n\n\n\n.. parsed-literal::\n\n    False\n\n\n\nOops! We forgot to reinitialize the object… (The formula is correct, but\nthe lattice is no longer commensurate so the FFT derivative has huge\nerrors).\n\n.. code:: ipython3\n\n    print(s.initialized)\n    s.init()\n    assert s.initialized\n    f = np.exp(3*np.cos(2*np.pi*s.x/s.L)) / 15\n    df = -2.*np.pi/5.*np.exp(3*np.cos(2*np.pi*s.x/s.L))*np.sin(2*np.pi*s.x/s.L)/s.L\n    np.allclose(s.compute_derivative(f), df)\n\n\n.. parsed-literal::\n\n    False\n    init() called\n\n\n\n\n.. parsed-literal::\n\n    True\n\n\n\nHere we demonstrate pickling. Note that using ``Object`` makes the\npickles very small, and when unpickled, ``init()`` is called to\nre-establish ``s.x`` and ``s.k``. Generally one would inherit from\n``Object``, but since we already have a class, we can provide pickling\nfunctionality with ``ObjectMixin``:\n\n.. code:: ipython3\n\n    class State1(ObjectMixin, State):\n        pass\n    \n    s = State(N=256, _quiet=True)\n    s1 = State1(N=256, _quiet=True)\n\n.. code:: ipython3\n\n    import pickle, copy\n    s_repr = pickle.dumps(s)\n    s1_repr = pickle.dumps(s1)\n    print(f"ObjectBase pickle:  {len(s_repr)} bytes")\n    print(f"ObjectMixin pickle: {len(s1_repr)} bytes")\n\n\n.. parsed-literal::\n\n    ObjectBase pickle:  4396 bytes\n    ObjectMixin pickle: 103 bytes\n\n\nNote, however, that the speed of copying is significantly impacted:\n\n.. code:: ipython3\n\n    %timeit copy.copy(s)\n    %timeit copy.copy(s1)\n\n\n.. parsed-literal::\n\n    2.58 µs ± 34.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n    27.1 µs ± 404 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n\n\nAnother use case applies when ``init()`` is expensive. If :math:`x` and\n:math:`k` were computed in ``__init__()``, then using properties to\nchange both :math:`N` and :math:`L` would trigger two updates. Here we\ndo the updates, then call ``init()``. Good practice is to call\n``init()`` automatically before any serious calculation to ensure that\nthe object is brought up to date before the computation.\n\n.. code:: ipython3\n\n    s.N = 64\n    s.L = 2.0\n    s.init()\n\nFinally, we demonstrate that ``Object`` instances can be archived using\nthe ``persist`` package:\n\n.. code:: ipython3\n\n    import persist.archive\n    a = persist.archive.Archive(check_on_insert=True)\n    a.insert(s=s)\n    \n    d = {}\n    exec(str(a), d)\n    \n    d[\'s\']\n\n\n\n\n.. parsed-literal::\n\n    State(L=2.0, N=64, _quiet=True)\n\n\n\nContainer\n~~~~~~~~~\n\nThe ``Container`` object is a slight extension of ``Object`` that\nprovides a simple container for storing data with attribute and\niterative access. These implement some of the `Collections Abstract Base\nClasses from the python standard\nlibrary <https://docs.python.org/2/library/collections.html#collections-abstract-base-classes>`__.\nThe following containers are provided:\n\n-  ``Container``: Bare-bones container extending the ``Sized``,\n   ``Iterable``, and ``Container`` abstract ase classes (ABCs) from the\n   standard ``containers`` library.\n-  ``ContainerList``: Extension that acts like a tuple/list satisfying\n   the ``Sequence`` ABC from the ``containers`` library (but not the\n   ``MutableSequence`` ABC. Although we allow setting and deleting\n   items, we do not provide a way for insertion, which breaks this\n   interface.)\n-  ``ContainerDict``: Extension that acts like a dict satisfying the\n   ``MutableMapping`` ABC from the ``containers`` library.\n\nThese were designed with the following use cases in mind:\n\n-  Returning data from a function associating names with each data. The\n   resulting ``ContainerList`` will act like a tuple, but will support\n   attribute access. Note that the order will be lexicographic. One\n   could use a dictionary, but attribute access with tab completion is\n   much nicer in an interactive session. The ``containers.nametuple``\n   generator could also be used, but this is somewhat more complicated\n   (though might be faster). Also, named tuples are immutable - here we\n   provide a mutable object that is picklable etc. The choice between\n   ``ContainerList`` and ``ContainerDict`` will depend on subsequent\n   usage. Containers can be converted from one type to another.\n\nContainer Examples\n^^^^^^^^^^^^^^^^^^\n\n.. code:: ipython3\n\n    from mmfutils.containers import Container\n    \n    c = Container(a=1, c=2, b=\'Hi there\')\n    print(c)\n    print(tuple(c))\n\n\n.. parsed-literal::\n\n    Container(a=1, b=\'Hi there\', c=2)\n    (1, \'Hi there\', 2)\n\n\n.. code:: ipython3\n\n    # Attributes are mutable\n    c.b = \'Ho there\'\n    print(c)\n\n\n.. parsed-literal::\n\n    Container(a=1, b=\'Ho there\', c=2)\n\n\n.. code:: ipython3\n\n    # Other attributes can be used for temporary storage but will not be pickled.\n    import numpy as np\n    \n    c.large_temporary_array = np.ones((256,256))\n    print(c)\n    print(c.large_temporary_array)\n\n\n.. parsed-literal::\n\n    Container(a=1, b=\'Ho there\', c=2)\n    [[1. 1. 1. ... 1. 1. 1.]\n     [1. 1. 1. ... 1. 1. 1.]\n     [1. 1. 1. ... 1. 1. 1.]\n     ...\n     [1. 1. 1. ... 1. 1. 1.]\n     [1. 1. 1. ... 1. 1. 1.]\n     [1. 1. 1. ... 1. 1. 1.]]\n\n\n.. code:: ipython3\n\n    import pickle\n    c1 = pickle.loads(pickle.dumps(c))\n    print(c1)\n    c1.large_temporary_array\n\n\n.. parsed-literal::\n\n    Container(a=1, b=\'Ho there\', c=2)\n\n\n::\n\n\n    ---------------------------------------------------------------------------\n\n    AttributeError                            Traceback (most recent call last)\n\n    <ipython-input-13-bd53d5116502> in <module>\n          2 c1 = pickle.loads(pickle.dumps(c))\n          3 print(c1)\n    ----> 4 c1.large_temporary_array\n    \n\n    AttributeError: \'Container\' object has no attribute \'large_temporary_array\'\n\n\nContexts\n--------\n\nThe ``mmfutils.contexts`` module provides two useful contexts:\n\n``NoInterrupt``: This can be used to susspend ``KeyboardInterrupt``\nexceptions until they can be dealt with at a point that is convenient. A\ntypical use is when performing a series of calculations in a loop. By\nplacing the loop in a ``NoInterrupt`` context, one can avoid an\ninterrupt from ruining a calculation:\n\n.. code:: ipython3\n\n    from mmfutils.contexts import NoInterrupt\n    \n    complete = False\n    n = 0\n    with NoInterrupt() as interrupted:\n        while not complete and not interrupted:\n            n += 1\n            if n > 10:\n                complete = True\n\nNote: One can nest ``NoInterrupt`` contexts so that outer loops are also\ninterrupted. Another use-case is mapping. See\n`doc/Animation.ipynb <Animation.ipynb>`__ for more examples.\n\n.. code:: ipython3\n\n    res = NoInterrupt().map(abs, range(-100, 100))\n    np.sign(res)\n\n\n\n\n.. parsed-literal::\n\n    array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n           1, 1])\n\n\n\nInterfaces\n----------\n\nThe interfaces module collects some useful\n`zope.interface <http://docs.zope.org/zope.interface/>`__ tools for\nchecking interface requirements. Interfaces provide a convenient way of\ncommunicating to a programmer what needs to be done to used your code.\nThis can then be checked in tests.\n\n.. code:: ipython3\n\n    from mmfutils.interface import Interface, Attribute, verifyClass, verifyObject, implementer\n    \n    class IAdder(Interface):\n        """Interface for objects that support addition."""\n    \n        value = Attribute(\'value\', "Current value of object")\n    \n        # No self here since this is the "user" interface\n        def add(other):\n            """Return self + other."""\n\nHere is a broken implementation. We muck up the arguments to ``add``:\n\n.. code:: ipython3\n\n    @implementer(IAdder)\n    class AdderBroken(object):\n        def add(self, one, another):\n            # There should only be one argument!\n            return one + another\n    \n    try:\n        verifyClass(IAdder, AdderBroken)\n    except Exception as e:\n        print("{0.__class__.__name__}: {0}".format(e))\n        \n\n\n.. parsed-literal::\n\n    BrokenMethodImplementation: The object <class \'__main__.AdderBroken\'> has failed to implement interface __main__.IAdder: The contract of __main__.IAdder.add(other) is violated because \'AdderBroken.add(self, one, another)\' requires too many arguments.\n\n\nNow we get ``add`` right, but forget to define ``value``. This is only\ncaught when we have an object since the attribute is supposed to be\ndefined in ``__init__()``:\n\n.. code:: ipython3\n\n    @implementer(IAdder)\n    class AdderBroken(object):\n        def add(self, other):\n            return one + other\n    \n    # The class validates...\n    verifyClass(IAdder, AdderBroken)\n    \n    # ... but objects are missing the value Attribute\n    try:\n        verifyObject(IAdder, AdderBroken())\n    except Exception as e:\n        print("{0.__class__.__name__}: {0}".format(e))    \n\n\n.. parsed-literal::\n\n    BrokenImplementation: The object <__main__.AdderBroken object at 0x11693cac0> has failed to implement interface __main__.IAdder: The __main__.IAdder.value attribute was not provided.\n\n\nFinally, a working instance:\n\n.. code:: ipython3\n\n    @implementer(IAdder)\n    class Adder(object):\n        def __init__(self, value=0):\n            self.value = value\n        def add(self, other):\n            return one + other\n        \n    verifyClass(IAdder, Adder) and verifyObject(IAdder, Adder())\n\n\n\n\n.. parsed-literal::\n\n    True\n\n\n\nInterface Documentation\n~~~~~~~~~~~~~~~~~~~~~~~\n\nWe also monkeypatch ``zope.interface.documentation.asStructuredText()``\nto provide a mechanism for documentating interfaces in a notebook.\n\n.. code:: ipython3\n\n    from mmfutils.interface import describe_interface\n    describe_interface(IAdder)\n\n\n\n\n.. raw:: html\n\n    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n    <head>\n    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n    <meta name="generator" content="Docutils 0.16: http://docutils.sourceforge.net/" />\n    <title>&lt;string&gt;</title>\n    \n    <div class="document">\n    \n    \n    <p><tt class="docutils literal">IAdder</tt></p>\n    <blockquote>\n    <p>Interface for objects that support addition.</p>\n    <p>Attributes:</p>\n    <blockquote>\n    <tt class="docutils literal">value</tt> -- Current value of object</blockquote>\n    <p>Methods:</p>\n    <blockquote>\n    <tt class="docutils literal">add(other)</tt> -- Return self + other.</blockquote>\n    </blockquote>\n    </div>\n\n\n\n\nParallel\n--------\n\nThe ``mmfutils.parallel`` module provides some tools for launching and\nconnecting to IPython clusters. The ``parallel.Cluster`` class\nrepresents and controls a cluster. The cluster is specified by the\nprofile name, and can be started or stopped from this class:\n\n.. code:: ipython3\n\n    import logging\n    logger = logging.getLogger()\n    logger.setLevel(logging.INFO)\n    import numpy as np\n    from mmfutils import parallel\n    cluster = parallel.Cluster(profile=\'default\', n=3, sleep_time=1.0)\n    cluster.start()\n    cluster.wait()  # Instance of IPython.parallel.Client\n    view = cluster.load_balanced_view\n    x = np.linspace(-6, 6, 100)\n    y = view.map(lambda x:x**2, x)\n    print(np.allclose(y, x**2))\n    cluster.stop()\n\n\n.. parsed-literal::\n\n    Waiting for connection file: ~/.ipython/profile_default/security/ipcontroller-client.json\n\n\n.. parsed-literal::\n\n    INFO:root:Starting cluster: ipcluster start --daemonize --quiet --profile=default --n=3\n\n\n.. parsed-literal::\n\n    Waiting for connection file: ~/.ipython/profile_default/security/ipcontroller-client.json\n\n\n.. parsed-literal::\n\n    INFO:root:waiting for 3 engines\n    INFO:root:0 of 3 running\n    INFO:root:3 of 3 running\n    INFO:root:Stopping cluster: ipcluster stop --profile=default\n\n\n.. parsed-literal::\n\n    True\n    Waiting for connection file: ~/.ipython/profile_default/security/ipcontroller-client.json\n\n\nIf you only need a cluster for a single task, it can be managed with a\ncontext. Be sure to wait for the result to be computed before exiting\nthe context and shutting down the cluster!\n\n.. code:: ipython3\n\n    with parallel.Cluster(profile=\'default\', n=3, sleep_time=1.0) as client:\n        view = client.load_balanced_view\n        x = np.linspace(-6, 6, 100)\n        y = view.map(lambda x:x**2, x, block=True)  # Make sure to wait for the result!\n    print(np.allclose(y, x**2))\n\n\n.. parsed-literal::\n\n    Waiting for connection file: ~/.ipython/profile_default/security/ipcontroller-client.json\n\n\n.. parsed-literal::\n\n    INFO:root:Starting cluster: ipcluster start --daemonize --quiet --profile=default --n=3\n\n\n.. parsed-literal::\n\n    Waiting for connection file: ~/.ipython/profile_default/security/ipcontroller-client.json\n\n\n.. parsed-literal::\n\n    INFO:root:waiting for 3 engines\n    INFO:root:0 of 3 running\n    INFO:root:3 of 3 running\n    INFO:root:Stopping cluster: ipcluster stop --profile=default\n\n\n.. parsed-literal::\n\n    Waiting for connection file: ~/.ipython/profile_default/security/ipcontroller-client.json\n    True\n\n\nIf you just need to connect to a running cluster, you can use\n``parallel.get_client()``.\n\nPerformance\n-----------\n\nThe ``mmfutils.performance`` module provides some tools for high\nperformance computing. Note: this module requires some additional\npackages including\n`numexp <https://github.com/pydata/numexpr/wiki/Numexpr-Users-Guide>`__,\n`pyfftw <http://hgomersall.github.io/pyFFTW/>`__, and the ``mkl``\npackage installed by anaconda. Some of these require building system\nlibraries (i.e.\xa0the `FFTW <http://www.fftw.org>`__). However, the\nvarious components will not be imported by default.\n\nHere is a brief description of the components:\n\n-  ``mmfutils.performance.blas``: Provides an interface to a few of the\n   scipy BLAS wrappers. Very incomplete (only things I currently need).\n-  ``mmfutils.performance.fft``: Provides an interface to the\n   `FFTW <http://www.fftw.org>`__ using ``pyfftw`` if it is available.\n   Also enables the planning cache and setting threads so you can better\n   control your performance.\n-  ``mmfutils.performance.numexpr``: Robustly imports numexpr and\n   disabling the VML. (If you don’t do this carefully, it will crash\n   your program so fast you won’t even get a traceback.)\n-  ``mmfutils.performance.threads``: Provides some hooks for setting the\n   maximum number of threads in a bunch of places including the MKL,\n   numexpr, and fftw.\n\nPlotting\n--------\n\nSeveral tools are provided in ``mmfutils.plot``:\n\nFast Filled Contour Plots\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\n``mmfutils.plot.imcontourf`` is similar to matplotlib’s ``plt.contourf``\nfunction, but uses ``plt.imshow`` which is much faster. This is useful\nfor animations and interactive work. It also supports my idea of saner\narray-shape processing (i.e.\xa0if ``x`` and ``y`` have different shapes,\nthen it will match these to the shape of ``z``). Matplotlib now provies\n``plt.pcolourmesh`` which is similar, but has the same interface issues.\n\n.. code:: ipython3\n\n    %matplotlib inline\n    from matplotlib import pyplot as plt\n    import time\n    import numpy as np\n    from mmfutils import plot as mmfplt\n    x = np.linspace(-1, 1, 100)[:, None]**3\n    y = np.linspace(-0.1, 0.1, 200)[None, :]**3\n    z = np.sin(10*x)*y**2\n    plt.figure(figsize=(12,3))\n    plt.subplot(141)\n    %time mmfplt.imcontourf(x, y, z, cmap=\'gist_heat\')\n    plt.subplot(142)\n    %time plt.contourf(x.ravel(), y.ravel(), z.T, 50, cmap=\'gist_heat\')\n    plt.subplot(143)\n    %time plt.pcolor(x.ravel(), y.ravel(), z.T, cmap=\'gist_heat\', shading=\'auto\')\n    plt.subplot(144)\n    %time plt.pcolormesh(x.ravel(), y.ravel(), z.T, cmap=\'gist_heat\', shading=\'auto\')\n\n\n.. parsed-literal::\n\n    CPU times: user 9.48 ms, sys: 3.72 ms, total: 13.2 ms\n    Wall time: 16.5 ms\n    CPU times: user 38.2 ms, sys: 2.97 ms, total: 41.2 ms\n    Wall time: 45 ms\n    CPU times: user 126 ms, sys: 5.86 ms, total: 132 ms\n    Wall time: 133 ms\n    CPU times: user 4.43 ms, sys: 209 µs, total: 4.64 ms\n    Wall time: 4.65 ms\n\n\n\n\n.. parsed-literal::\n\n    <matplotlib.collections.QuadMesh at 0x124ec2130>\n\n\n\n\n.. image:: README_files/README_60_2.png\n\n\nAngular Variables\n-----------------\n\nA couple of tools are provided to visualize angular fields, such as the\nphase of a complex wavefunction.\n\n.. code:: ipython3\n\n    %matplotlib inline\n    from matplotlib import pyplot as plt\n    import time\n    import numpy as np\n    from mmfutils import plot as mmfplt\n    x = np.linspace(-1, 1, 100)[:, None]\n    y = np.linspace(-1, 1, 200)[None, :]\n    z = x + 1j*y\n    \n    plt.figure(figsize=(9,2))\n    ax = plt.subplot(131)\n    mmfplt.phase_contour(x, y, z, colors=\'k\', linewidths=0.5)\n    ax.set_aspect(1)\n    \n    # This is a little slow but allows you to vary the luminosity.\n    ax = plt.subplot(132)\n    mmfplt.imcontourf(x, y, mmfplt.colors.color_complex(z))\n    mmfplt.phase_contour(x, y, z, linewidths=0.5)\n    ax.set_aspect(1)\n    \n    # This is faster if you just want to show the phase and allows\n    # for a colorbar via a registered colormap\n    ax = plt.subplot(133)\n    mmfplt.imcontourf(x, y, np.angle(z), cmap=\'huslp\')\n    ax.set_aspect(1)\n    plt.colorbar()\n    mmfplt.phase_contour(x, y, z, linewidths=0.5);\n\n\n\n.. image:: README_files/README_63_0.png\n\n\nDebugging\n---------\n\nA couple of debugging tools are provided. The most useful is the\n``debug`` decorator which will store the local variables of a function\nin a dictionary or in your global scope.\n\n.. code:: ipython3\n\n    from mmfutils.debugging import debug\n    \n    @debug(locals())\n    def f(x):\n        y = x**1.5\n        z = 2/x\n        return z\n    \n    print(f(2.0), x, y, z)\n\n\n.. parsed-literal::\n\n    1.0 2.0 2.8284271247461903 1.0\n\n\nMathematics\n-----------\n\nWe include a few mathematical tools here too. In particular, numerical\nintegration and differentiation. Check the API documentation for\ndetails.\n\nDeveloper Instructions\n======================\n\nComplete code coverage information is provided in\n``build/_coverage/index.html``.\n\n.. code:: ipython3\n\n    from IPython.display import HTML\n    with open(os.path.join(ROOTDIR, \'build/_coverage/index.html\')) as f:\n        coverage = f.read()\n    HTML(coverage)\n\n\n\n\n.. raw:: html\n\n    <!DOCTYPE html>\n    <html>\n    <head>\n        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n        <title>Coverage report</title>\n        <link rel="icon" sizes="32x32" href="favicon_32.png">\n        <link rel="stylesheet" href="style.css" type="text/css">\n        <script type="text/javascript" src="jquery.min.js"></script>\n        <script type="text/javascript" src="jquery.ba-throttle-debounce.min.js"></script>\n        <script type="text/javascript" src="jquery.tablesorter.min.js"></script>\n        <script type="text/javascript" src="jquery.hotkeys.js"></script>\n        <script type="text/javascript" src="coverage_html.js"></script>\n        <script type="text/javascript">\n            jQuery(document).ready(coverage.index_ready);\n        </script>\n    </head>\n    <body class="indexfile">\n    <div id="header">\n        <div class="content">\n            <h1>Coverage report:\n                <span class="pc_cov">90%</span>\n            </h1>\n            <img id="keyboard_icon" src="keybd_closed.png" alt="Show keyboard shortcuts" />\n            <form id="filter_container">\n                <input id="filter" type="text" value="" placeholder="filter..." />\n            </form>\n        </div>\n    </div>\n    <div class="help_panel">\n        <img id="panel_icon" src="keybd_open.png" alt="Hide keyboard shortcuts" />\n        <p class="legend">Hot-keys on this page</p>\n        <div>\n        <p class="keyhelp">\n            <span class="key">n</span>\n            <span class="key">s</span>\n            <span class="key">m</span>\n            <span class="key">x</span>\n            <span class="key">c</span> &nbsp; change column sorting\n        </p>\n        </div>\n    </div>\n    <div id="index">\n        <table class="index">\n            <thead>\n                <tr class="tablehead" title="Click to sort">\n                    <th class="name left headerSortDown shortkey_n">Module</th>\n                    <th class="shortkey_s">statements</th>\n                    <th class="shortkey_m">missing</th>\n                    <th class="shortkey_x">excluded</th>\n                    <th class="right shortkey_c">coverage</th>\n                </tr>\n            </thead>\n            <tfoot>\n                <tr class="total">\n                    <td class="name left">Total</td>\n                    <td>2209</td>\n                    <td>213</td>\n                    <td>85</td>\n                    <td class="right" data-ratio="1996 2209">90%</td>\n                </tr>\n            </tfoot>\n            <tbody>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils___init___py.html">mmfutils/__init__.py</a></td>\n                    <td>13</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="13 13">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_containers_py.html">mmfutils/containers.py</a></td>\n                    <td>113</td>\n                    <td>2</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="111 113">98%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_contexts_py.html">mmfutils/contexts.py</a></td>\n                    <td>199</td>\n                    <td>25</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="174 199">87%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_debugging_py.html">mmfutils/debugging.py</a></td>\n                    <td>49</td>\n                    <td>0</td>\n                    <td>3</td>\n                    <td class="right" data-ratio="49 49">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_interface_py.html">mmfutils/interface.py</a></td>\n                    <td>77</td>\n                    <td>0</td>\n                    <td>15</td>\n                    <td class="right" data-ratio="77 77">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math___init___py.html">mmfutils/math/__init__.py</a></td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="0 0">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_bases___init___py.html">mmfutils/math/bases/__init__.py</a></td>\n                    <td>2</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="2 2">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_bases_bases_py.html">mmfutils/math/bases/bases.py</a></td>\n                    <td>431</td>\n                    <td>52</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="379 431">88%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_bases_interfaces_py.html">mmfutils/math/bases/interfaces.py</a></td>\n                    <td>37</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="37 37">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_bases_utils_py.html">mmfutils/math/bases/utils.py</a></td>\n                    <td>41</td>\n                    <td>11</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="30 41">73%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_bessel_py.html">mmfutils/math/bessel.py</a></td>\n                    <td>132</td>\n                    <td>0</td>\n                    <td>14</td>\n                    <td class="right" data-ratio="132 132">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_differentiate_py.html">mmfutils/math/differentiate.py</a></td>\n                    <td>61</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="61 61">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_integrate___init___py.html">mmfutils/math/integrate/__init__.py</a></td>\n                    <td>212</td>\n                    <td>12</td>\n                    <td>16</td>\n                    <td class="right" data-ratio="200 212">94%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_linalg_py.html">mmfutils/math/linalg.py</a></td>\n                    <td>12</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="12 12">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_special_py.html">mmfutils/math/special.py</a></td>\n                    <td>26</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="26 26">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_math_wigner_py.html">mmfutils/math/wigner.py</a></td>\n                    <td>20</td>\n                    <td>17</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="3 20">15%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_optimize_py.html">mmfutils/optimize.py</a></td>\n                    <td>26</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="26 26">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_parallel_py.html">mmfutils/parallel.py</a></td>\n                    <td>128</td>\n                    <td>5</td>\n                    <td>8</td>\n                    <td class="right" data-ratio="123 128">96%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_performance___init___py.html">mmfutils/performance/__init__.py</a></td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="0 0">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_performance_blas_py.html">mmfutils/performance/blas.py</a></td>\n                    <td>58</td>\n                    <td>0</td>\n                    <td>6</td>\n                    <td class="right" data-ratio="58 58">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_performance_fft_py.html">mmfutils/performance/fft.py</a></td>\n                    <td>92</td>\n                    <td>3</td>\n                    <td>6</td>\n                    <td class="right" data-ratio="89 92">97%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_performance_numexpr_py.html">mmfutils/performance/numexpr.py</a></td>\n                    <td>9</td>\n                    <td>0</td>\n                    <td>7</td>\n                    <td class="right" data-ratio="9 9">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_performance_threads_py.html">mmfutils/performance/threads.py</a></td>\n                    <td>9</td>\n                    <td>0</td>\n                    <td>8</td>\n                    <td class="right" data-ratio="9 9">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_plot___init___py.html">mmfutils/plot/__init__.py</a></td>\n                    <td>4</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="4 4">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_plot_animation_py.html">mmfutils/plot/animation.py</a></td>\n                    <td>82</td>\n                    <td>19</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="63 82">77%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_plot_cmaps_py.html">mmfutils/plot/cmaps.py</a></td>\n                    <td>10</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="10 10">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_plot_rasterize_py.html">mmfutils/plot/rasterize.py</a></td>\n                    <td>29</td>\n                    <td>1</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="28 29">97%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_solve___init___py.html">mmfutils/solve/__init__.py</a></td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="0 0">100%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_solve_broyden_py.html">mmfutils/solve/broyden.py</a></td>\n                    <td>319</td>\n                    <td>64</td>\n                    <td>0</td>\n                    <td class="right" data-ratio="255 319">80%</td>\n                </tr>\n                <tr class="file">\n                    <td class="name left"><a href="mmfutils_testing_py.html">mmfutils/testing.py</a></td>\n                    <td>18</td>\n                    <td>2</td>\n                    <td>2</td>\n                    <td class="right" data-ratio="16 18">89%</td>\n                </tr>\n            </tbody>\n        </table>\n        <p id="no_rows">\n            No items found using the specified filter.\n        </p>\n    </div>\n    <div id="footer">\n        <div class="content">\n            <p>\n                <a class="nav" href="https://coverage.readthedocs.io">coverage.py v5.5</a>,\n                created at 2021-04-28 01:48 -0700\n            </p>\n        </div>\n    </div>\n    </body>\n    </html>\n\n\n\n\nChange Log\n==========\n\nREL: 0.5.4\n----------\n\n-  Drop support for Python 3.5.\n-  Use `Nox <https://nox.thea.codes>`__ for testing (see\n   `Notes.md <../Notes.md>`__)\n\nREL: 0.5.3\n----------\n\nAllow Python 3.8. Previous version required ``python <= 3.7`` due to an\n`issue with\nipyparallel <https://github.com/ipython/ipyparallel/issues/396>`__. This\nhas been resolved with revision 6.2.5 which is available with ``conda``.\n\nREL: 0.5.1\n----------\n\nAPI changes:\n\n-  Split ``mmfutils.containers.Object`` into ``ObjectBase`` which is\n   simple and ``ObjectMixin`` which provides the picking support.\n   Demonstrate in docs how the pickling can be useful, but slows\n   copying.\n\nREL: 0.5.0\n----------\n\nAPI changes:\n\n-  Python 3 support only.\n-  ``mmfutils.math.bases.interface`` renamed to\n   ``mmfutils.math.bases.interfaces``.\n-  Added default class-variable attribute support to\n   e\\ ``mmfutils.containers.Object``.\n-  Minor enhancements to ``mmfutils.math.bases.PeriodicBasis`` to\n   enhance GPU support.\n-  Added ``mmfutils.math.bases.interfaces.IBasisLz`` and support in\n   ``mmfutils.math.bases.bases.PeriodicBasis`` for rotating frames.\n-  Cleanup of build environment and tests.\n\n   -  Single environment ``_mmfutils`` now used for testing and\n      documentation.\n\nREL: 0.4.13\n-----------\n\nAPI changes:\n\n-  Use ``@implementer()`` class decorator rather than\n   ``classImplements`` or ``implements`` in all interfaces.\n-  Improve ``NoInterrupt`` context. Added ``NoInterrupt.unregister()``:\n   this allows ``NoInterrupt`` to work in a notebook cell even when the\n   signal handlers are reset. (But only works in that one cell.)\n-  Added Abel transform ``integrate2`` to Cylindrical bases.\n\nIssues:\n\n-  Resolved issue #22: Masked arrays work with ``imcontourf`` etc.\n-  Resolved issue #23: ``NoInterrupt`` works well except in notebooks\n   due to `ipykernel issue\n   #328 <https://github.com/ipython/ipykernel/issues/328>`__.\n-  Resolved issue #24: Python 3 is now fully supported and tested.\n\nREL: 0.4.10\n-----------\n\nAPI changes:\n\n-  Added ``contourf``, ``error_line``, and ``ListCollections`` to\n   ``mmfutils.plot``.\n-  Added Python 3 support (still a couple of issues such as\n   ``mmfutils.math.integrate.ssum_inline``.)\n-  Added ``mmf.math.bases.IBasisKx`` and update ``lagrangian`` in bases\n   to accept ``k2`` and ``kx2`` for modified dispersion control (along\n   x).\n-  Added ``math.special.ellipkinv``.\n-  Added some new ``mmfutils.math.linalg`` tools.\n\nIssues:\n\n-  Resolved issue #20: ``DyadicSum`` and\n   ``scipy.optimize.nonlin.Jacobian``\n-  Resolved issue #22: imcontourf now respects masked arrays.\n-  Resolved issue #24: Support Python 3.\n\nREL: 0.4.9\n----------\n\n*< incomplete >*\n\nREL: 0.4.7\n----------\n\nAPI changes:\n\n-  Added ``mmfutils.interface.describe_interface()`` for inserting\n   interfaces into documentation.\n-  Added some DVR basis code to ``mmfutils.math.bases``.\n-  Added a diverging colormap and some support in ``mmfutils.plot``.\n-  Added a Wigner Ville distribution computation in\n   ``mmfutils.math.wigner``\n-  Added ``mmfutils.optimize.usolve`` and ``ubrentq`` for finding roots\n   with ```uncertanties`` <https://pythonhosted.org/uncertainties/>`__\n   support.\n\nIssues:\n\n-  Resolve issue #8: Use\n   ```ipyparallel`` <https://github.com/ipython/ipyparallel>`__ now.\n-  Resolve issue #9: Use `pytest <https://pytest.org>`__ rather than\n   ``nose`` (which is no longer supported).\n-  Resolve issue #10: PYFFTW wrappers now support negative ``axis`` and\n   ``axes`` arguments.\n-  Address issue #11: Preliminary version of some DVR basis classes.\n-  Resolve issue #12: Added solvers with\n   ```uncertanties`` <https://pythonhosted.org/uncertainties/>`__\n   support.\n',
    'author': 'Michael McNeil Forbes',
    'author_email': 'michael.forbes+python@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://alum.mit.edu/www/mforbes/hg/forbes-group/mmfutils',
    'package_dir': package_dir,
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.6.2,<3.10',
}


setup(**setup_kwargs)
