{ "info": { "author": "Alvaro Sanchez-Gonzalez", "author_email": "sanchezgnzlz.alvaro@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Build Tools" ], "description": "pynverse |PyPI version|\r\n=======================\r\n\r\nA module specialized on calculating the numerical inverse of any\r\ninvertible continuous function.\r\n\r\nRequirements\r\n------------\r\n\r\n|Scipy| |Numpy|\r\n\r\nInstall\r\n-------\r\n\r\nIn order to install this tool you'll need ``pip``:\r\n\r\n::\r\n\r\n pip install pynverse\r\n\r\nUsage\r\n-----\r\n\r\nPynverse provides a main function ``inversefunc`` that calculates the\r\nnumerical inverse of a function ``f`` passed as the first argument in\r\nthe form of a callable.\r\n\r\n.. code:: python\r\n\r\n >>> from pynverse import inversefunc\r\n\r\nIt can be used to calculate the inverse function at certain ``y_values``\r\npoints:\r\n\r\n.. code:: python\r\n\r\n >>> cube = (lambda x: x**3)\r\n >>> invcube = inversefunc(cube, y_values=3)\r\n array(3.0000000063797567)\r\n\r\nOr to obtain a callable that will calculate the inverse values at any\r\nother points if ``y_values`` is not provided:\r\n\r\n.. code:: python\r\n\r\n >>> invcube = inversefunc(cube)\r\n >>> invcube(27)\r\n array(3.0000000063797567)\r\n\r\nIt requires the function to be continuous and strictly monotonic (i.e.\r\npurely decreasing or purely increasing) within the domain of the\r\nfunction. By default, the domain includes all real numbers, but it can\r\nbe restricted to an inverval using the ``domain`` argument:\r\n\r\n.. code:: python\r\n\r\n >>> import numpy as np\r\n >>> inversefunc(np.cos, y_values=[1, 0, -1], # Should give [0, pi / 2, pi]\r\n ... domain=[0, np.pi])\r\n array([ 0. , 1.57079632, 3.14159265])\r\n\r\nAdditionally, the argument ``open_domain`` can be used to specify the\r\nopen/closed character of each of the ends of the domain interval:\r\n\r\n.. code:: python\r\n\r\n >>> inversefunc(np.log10, y_values=-2, # Should give 0.01\r\n ... domain=0, open_domain=[True, False])\r\n array(0.0099999999882423)\r\n\r\nOr on both ends simultaneously:\r\n\r\n.. code:: python\r\n\r\n >>> invtan = inversefunc(np.tan,\r\n ... domain=[-np.pi / 2, np.pi / 2],\r\n ... open_domain=True)\r\n >>> invtan([1, 0, -1]) # Should give [pi / 4, 0, -pi / 4]\r\n array([ 7.85398163e-01, 1.29246971e-26, -7.85398163e-01])\r\n\r\nAdditional parameters may be passed to the function for easier\r\nreusability of callables using the ``args`` argument:\r\n\r\n.. code:: python\r\n\r\n >>> invsquare = inversefunc(np.power, args=(2), domain=0)\r\n >>> invsquare([4, 16, 64])\r\n array([ 2., 4., 8.])\r\n\r\nThe image of the function in the interval may be also provided for cases\r\nwhere the function is non continuous right at the end of an open\r\ninterval with the ``image`` argument:\r\n\r\n.. code:: python\r\n\r\n >>> invmod = inversefunc(np.mod, args=(1), domain=[5,6], \r\n ... open_domain=[False,True], image=[0,1])\r\n >>> invmod([0.,0.3,0.5])\r\n array([ 5. , 5.3, 5.5])\r\n\r\nAdditionally an argument can be used to check for the number of digits\r\nof accuracy in the results, giving a warning in case this is not meet:\r\n\r\n.. code:: python\r\n\r\n >>> inversefunc(np.log10, y_values=-8, # Should give 0.01\r\n ... domain=0, open_domain=True, accuracy=6)\r\n pynverse\\inverse.py:195: RuntimeWarning: Results obtained with less than 6 decimal digits of accuracy\r\n array(9.999514710830838e-09)\r\n\r\nAs it is compatible with arrays, it can very easily used to obtain the\r\ninverse for broad ranges. These are some examples of using the returned\r\nnumerical inverse callables with arrays to make plots, and compare them\r\nto the analytical inverse, each of them calculated as simply as:\r\n\r\n.. code:: python\r\n\r\n log = lambda x: np.log10(x)\r\n invlog = scipy.misc.inversefunc(log, domain=0, open_domain=True)\r\n x1=np.linspace(0.00001,10,100)\r\n x2=np.linspace(-5,1,100)\r\n ax1.plot(x1,log(y1),'b-')\r\n ax2.plot(x2,invlog(x2),'b-')\r\n\r\n invlog_a = lambda x: 10**x\r\n ax2.plot(x2,invlog_a(x2),'r--')\r\n\r\n.. figure:: https://cloud.githubusercontent.com/assets/12649253/19738042/cf22460a-9bad-11e6-9c17-6fdd6cda0991.png\r\n :alt: \r\n\r\nIn particular, for the definition of piecewise functions, there is a\r\n``piecewise`` utility function provided that solves the issues of\r\nnp.piecewise when working with both scalars and arrays. For example, the\r\ninverse for the last plot was obtained as:\r\n\r\n.. code:: python\r\n\r\n from pynverse import inversefunc, piecewise\r\n\r\n pw=lambda x: piecewise(x,[x<1,(x>=1)*(x<3),x>=3],[lambda x: x, lambda x: x**2, lambda x: x+6])\r\n invpw =inversefunc(pw) \r\n\r\nDisclaimer\r\n----------\r\n\r\nThe problem of calculating the numerical inverse of an arbitrary funtion\r\nin unlimited or open intervals is still an open question in applied\r\nmathematics. The main purpose of this package is not to be fast, or as\r\naccurate as it could be if the inverse was calculated specifically for a\r\nknown function, using more specialised techniques. The current\r\nimplementation essentially uses the existing tools in scipy to solve the\r\nparticular problem of finding the inverse of a function meeting the\r\ncontinuity and monotonicity conditions, but while it performs really\r\nwell it may fail under certain conditions. For example when inverting a\r\n``log10`` it is known to start giving inccacurate values when being\r\nasked to invert -10, which should correspond to 0.0000000001 (1e-10),\r\nbut gives instead 0.0000000000978 (0.978e-10).\r\n\r\nThe advantage about estimating the inverse function is that the accuracy\r\ncan always be verified by checking if f(finv(x))==x..\r\n\r\nDetails about the implementation\r\n--------------------------------\r\n\r\nThe summarized internal strategy is the following:\r\n\r\n1. Figure out if the function is increasing or decreasing. For this two\r\n reference points ref1 and ref2 are needed:\r\n\r\n - In case of a finite interval, the points ref points are 1/4 and\r\n 3/4 through the interval.\r\n - In an infinite interval any two values work really.\r\n - If f(ref1)