diff --git a/.gitignore b/.gitignore index 01dfddb..0df7ce3 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,10 @@ htmlcov/ /.cache/ /.ipynb_checkpoints/ /.settings/ + +**/.*.sw? +venv* +sandbox + +**/.DS_Store +.python-version diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..1dbd1dc --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,53 @@ +stages: + - style + - test_code + - test_and_create_docs + - publish_docs + +tests: + tags: + - python + script: + - pyenv versions + - pyenv local 2.7 3.4.6 3.5.3 3.6.2 + - tox -r -vv -i https://cosmo-pypi.phys.ethz.ch/simple + stage: test_code + artifacts: + paths: + - htmlcov/ + +style: + tags: + - python + script: + - pyenv local 2.7 3.4.6 3.5.3 3.6.2 + - tox -e style -i https://cosmo-pypi.phys.ethz.ch/simple + allow_failure: true + stage: style + + +docs: + tags: + - python + script: + - pyenv local 2.7 3.4.6 3.5.3 3.6.2 + - tox -e docs -i https://cosmo-pypi.phys.ethz.ch/simple + stage: test_and_create_docs + dependencies: + - tests + artifacts: + paths: + - docs/_build + +publish_docs: + tags: + - python + script: + - publish_docs docs/_build hope + - create_index_html + when: manual + stage: publish_docs + dependencies: + - docs + only: + - master diff --git a/.travis.yml b/.travis.yml index 5edec16..7d05adb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ python: before_install: - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - sudo apt-get -qq update - - sudo apt-get -qq install g++-4.8 gcc-4.8 + - sudo apt-get -qq install g++-4.8 gcc-4.8 llvm-4.0-dev - sudo ln -sf /usr/bin/gcc-4.8 /usr/bin/gcc - sudo ln -sf /usr/bin/g++-4.8 /usr/bin/g++ # We do this conditionally because it saves us some downloading if the diff --git a/AUTHORS.rst b/AUTHORS.rst index 5e73ffa..a84b4ec 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -20,6 +20,7 @@ We would like to thank several people for helping to test this package before re * Chihway Chang * Sebastian Gaebel * Joerg Herbel +* Uwe Schmitt Citations @@ -35,4 +36,4 @@ Feedback If you have any suggestions or questions about **HOPE** feel free to email me at hope@phys.ethz.ch. -If you encounter any errors or problems with **HOPE**, please let me know! \ No newline at end of file +If you encounter any errors or problems with **HOPE**, please let me know! diff --git a/HISTORY.rst b/HISTORY.rst index 89b5efd..f33c751 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -2,6 +2,13 @@ History ------- + +0.7.0 (2017-09-08) +++++++++++++++++++ + +* Support for Python 3.5 and 3.6 + + 0.6.1 (2016-07-04) ++++++++++++++++++ @@ -90,4 +97,4 @@ AugBitAnd ``a & b`` 0.1.0 (2014-02-27) ++++++++++++++++++ -* Initial creation. \ No newline at end of file +* Initial creation. diff --git a/Makefile b/Makefile index cba4c2d..4d78790 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ lint: flake8 hope test test: - py.test -v -s + py.test -v -s test test-all: tox @@ -48,4 +48,4 @@ docs: sdist: clean #pip freeze > requirements.rst python setup.py sdist - ls -l dist \ No newline at end of file + ls -l dist diff --git a/README.rst b/README.rst index 9d434ad..dcc2075 100644 --- a/README.rst +++ b/README.rst @@ -5,23 +5,26 @@ HOPE - combine the ease of Python and the speed of C++ .. image:: https://badge.fury.io/py/hope.svg :target: http://badge.fury.io/py/hope -.. image:: https://travis-ci.org/cosmo-ethz/hope.svg?branch=master - :target: https://travis-ci.org/cosmo-ethz/hope - -.. image:: https://coveralls.io/repos/cosmo-ethz/hope/badge.svg?branch=master - :target: https://coveralls.io/r/cosmo-ethz/hope?branch=master - -.. image:: https://img.shields.io/badge/docs-latest-blue.svg?style=flat - :target: http://hope.readthedocs.org/en/latest - .. image:: http://img.shields.io/badge/arXiv-1410.4345-brightgreen.svg?style=flat :target: http://arxiv.org/abs/1410.4345 +.. image:: https://cosmo-gitlab.phys.ethz.ch/cosmo/hope/badges/master/build.svg + +.. image:: https://cosmo-gitlab.phys.ethz.ch/cosmo/hope/badges/master/coverage.svg -**HOPE** is a specialized method-at-a-time JIT compiler written in Python for translating Python source code into C++ and compiles this at runtime. In contrast to other existing JIT compliers, which are designed for general purpose, we have focused our development of the subset of the Python language that is most relevant for astrophysical calculations. By concentrating on this subset, **HOPE** is able to achieve the highest possible performance +**HOPE** is a specialized method-at-a-time JIT compiler written in Python for +translating Python source code into C++ and compiles this at runtime. In +contrast to other existing JIT compliers, which are designed for general +purpose, we have focused our development of the subset of the Python language +that is most relevant for astrophysical calculations. By concentrating on this +subset, **HOPE** is able to achieve the highest possible performance. -By using **HOPE**, the user can benefit from being able to write common numerical code in Python and having the performance of compiled implementation. To enable the **HOPE** JIT compilation, the user needs to add a decorator to the function definition. The package does not require additional information, which ensures that **HOPE** is as non-intrusive as possible: +By using **HOPE**, the user can benefit from being able to write common +numerical code in Python and having the performance of compiled implementation. +To enable the **HOPE** JIT compilation, the user needs to add a decorator to +the function definition. The package does not require additional information, +which ensures that **HOPE** is as non-intrusive as possible: .. code-block:: python @@ -31,15 +34,28 @@ By using **HOPE**, the user can benefit from being able to write common numerica def sum(x, y): return x + y - -The **HOPE** package has been developed at ETH Zurich in the `Software Lab of the Cosmology Research Group `_ of the `ETH Institute of Astronomy `_, and is now publicly available at `GitHub `_. -Further information on the package can be found in our `paper `_, on `readthedocs.org `_ and on our `website `_. +The **HOPE** package has been developed at ETH Zurich in the `Software Lab of +the Cosmology Research Group +`_ of the `ETH +Institute of Astronomy `_, and is now publicly +available at `GitHub `_. + +Further information on the package can be found in our `paper +`_, on +`readthedocs.org `_ and on our +`website `_. + +Python versions supported +------------------------- + +Hope supports Python versions from `2.7` up to `3.6`. Installation ------------ -The package has been uploaded to `PyPI `_ and can be installed at the command line via pip:: +The package has been uploaded to `PyPI `_ +and can be installed at the command line via pip:: $ pip install hope diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore index 88901c5..f4679ed 100644 --- a/benchmarks/.gitignore +++ b/benchmarks/.gitignore @@ -5,3 +5,6 @@ /star.py /util.py /.ipynb_checkpoints/ +hope/ +*.html + diff --git a/benchmarks/HPC Python.ipynb b/benchmarks/HPC Python.ipynb index 37420b8..a7bb615 100644 --- a/benchmarks/HPC Python.ipynb +++ b/benchmarks/HPC Python.ipynb @@ -1,535 +1,438 @@ { - "metadata": { - "name": "", - "signature": "sha256:bc54c0a983314fa977f09e4ffb2a2c91ee6f84fd2477d2ff297f27cc2b72d428" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import hope\n", - "hope.config.optimize = True\n", - "hope.config.keeptemp = True\n", - "import numpy as np\n", - "from matplotlib import pyplot as plt\n", - "%pylab inline" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Populating the interactive namespace from numpy and matplotlib\n" - ] - } - ], - "prompt_number": 1 - }, + "cell_type": "code", + "execution_count": 1, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ { - "cell_type": "heading", - "level": 1, - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "source": [ - "Python Optimizations" + "name": "stdout", + "output_type": "stream", + "text": [ + "Populating the interactive namespace from numpy and matplotlib\n" ] - }, + } + ], + "source": [ + "import hope\n", + "hope.config.optimize = True\n", + "hope.config.keeptemp = True\n", + "import numpy as np\n", + "from matplotlib import pyplot as plt\n", + "import warnings\n", + "# warnings.filterwarnings(\"ignore\", category=UserWarning) \n", + "\n", + "\n", + "%pylab inline" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Python Optimizations" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Avoid memory allocations" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**zombie apocalypse modeling** from http://wiki.scipy.org/Cookbook/Zombie_Apocalypse_ODEINT" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from scipy.integrate import odeint\n", + "\n", + "P, d, B, G, A = 0, 0.0001, 0.0095, 0.0001, 0.0001\n", + "\n", + "def f_nat(y, t):\n", + " dy = np.empty(3)\n", + " dy[0] = P - B*y[0]*y[1] - d*y[0]\n", + " dy[1] = B*y[0]*y[1] + G*y[2] - A*y[0]*y[1]\n", + " dy[2] = d*y[0] + A*y[0]*y[1] - G*y[2]\n", + " return dy\n", + "\n", + "y0, t = np.array([500., .001, 0.]), np.linspace(0, 5., 1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, + "data": { + "image/png": "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\nYII=\n", + "text/plain": [ + "" + ] + }, "metadata": {}, - "source": [ - "Avoid memory allocations" - ] - }, + "output_type": "display_data" + } + ], + "source": [ + "soln = odeint(f_nat, y0, t)\n", + "plt.figure()\n", + "plt.plot(t, soln[:, 0], label='Living')\n", + "plt.plot(t, soln[:, 1], label='Zombies')\n", + "plt.xlabel('Days from outbreak')\n", + "plt.ylabel('Population')\n", + "plt.legend(loc=0)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**zombie apocalypse modeling** from http://wiki.scipy.org/Cookbook/Zombie_Apocalypse_ODEINT" + "name": "stdout", + "output_type": "stream", + "text": [ + "native python\n", + "1.53 ms ± 29.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "hope\n", + "266 µs ± 24.3 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "hope without allocation\n", + "237 µs ± 19.2 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from scipy.integrate import odeint\n", - "\n", - "P, d, B, G, A = 0, 0.0001, 0.0095, 0.0001, 0.0001\n", - "\n", - "def f_nat(y, t):\n", - " dy = np.empty(3)\n", - " dy[0] = P - B*y[0]*y[1] - d*y[0]\n", - " dy[1] = B*y[0]*y[1] + G*y[2] - A*y[0]*y[1]\n", - " dy[2] = d*y[0] + A*y[0]*y[1] - G*y[2]\n", - " return dy\n", - "\n", - "y0, t = np.array([500., 0., 5.]), np.linspace(0, 5., 1000)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "soln = odeint(f_nat, y0, t)\n", - "plt.figure()\n", - "plt.plot(t, soln[:, 0], label='Living')\n", - "plt.plot(t, soln[:, 1], label='Zombies')\n", - "plt.xlabel('Days from outbreak')\n", - "plt.ylabel('Population')\n", - "plt.legend(loc=0)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\nCLPk4uLCZ599xkcffQToP83279+fHj160KNHDw4cOABARETENdOgT548mU2bNvHnn38SFBREYGAg\n/v7+JCUlXbP/119/nf379zNjxgxeeOEFli5dyvDhwwkNDSUsLIzz588zcuRI/P39ufvuuw3rTkRG\nRhIREUH//v3x9vZm/fr1/Otf/8LPz48hQ4ZQXl5+w+9y+PBhevfujb+/P6NHjzZMLxEcHExcXByg\nn3bCx8eHsrIyXnvtNdasWUNgYCBr164F9K2GPn360KFDB7744gsAYmJi6NevHyNGjKBr167odDqe\nf/55evXqhb+/P5999hmgn/hv4MCB9OjRAz8/v5uuDXDq1Cm6d+9uyCOslCKEmWjcuPENtzk5OSk5\nOTlKUVGRUlJSoiiKoiQmJio9e/ZUFEVRfvjhB2XkyJGKoihKfn6+4uPjo5SXlyuzZs1SVq5cqSiK\nopSVlSnFxcU37Ds4OFiJi4tTFEVRlixZonh5eSnnz59XFEVRZs2apbz++uuKoijKnj17lICAAEVR\nFGXu3LlKv379lPLycuX3339XGjZsqGzfvl1RFEUZNWqUsmHDhhuO061bN+XHH39UFEVRXnvtNeWZ\nZ5654fi5ubmKt7e3oiiK8tVXXylPPvmk4flz585V/P39lZKSEuXs2bNKq1atlIyMDGXv3r1Ko0aN\nlJSUFEVRFOXTTz9V3nzzTUVRFKWkpETp2bOnkpycrJSXlysFBQWG4/j6+iqKoijJyclK165dlePH\njyuBgYHKkSNHbvGvI6yBtDFFnVBaWsqsWbP4/fffsbW1JTExEYD+/fszc+ZMzp49y7p16xg7diy2\ntrb06dOHf//736SlpTF69Gh8fX2rPEZYWBhOTk6Afo6k9evXAxASEsK5c+e4ePEiGo2GIUOGYGtr\na/hUPmjQIAC6detGSkrKNfu8cOECFy5coF+/foC+RTNu3Lhb5lAU5ZpzJxqNhpEjR1K/fn3q169P\nSEgIsbGxODk50atXL9q0aQPAjh07OHr0KOvWrQOgoKCApKQkvLy8mDNnDvv27cPGxoaMjAxycnIA\nyMnJYeTIkXz33Xd06tSpytdIWDbpMhJm69SpU9ja2uLi4sIHH3yAh4cHR44c4dChQ5SWlhoeN23a\nNJYvX85XX33FjBkzAP0EgJs3b6Zhw4bcd9997N2795bH0mg0NGrU6JrblEpOaNerVw/Qrz1gb29v\nuN3GxuamXUaV7dPOzg6dTgfo10OuiasLv1yf+aOPPiI+Pp74+HhOnjzJwIEDWbFiBWfPnuW3334j\nPj4eV1dXw/GcnJxo06ZNpfPjC+siBUGYpdzcXB5//HGefPJJQP9p193dHYBly5ZRUVFheOz06dP5\n8MMP0Wg0hk+5ycnJ+Pj48OSTTzJixIgq156+/s2/X79+rFy5EtD31bu4uODo6FjjUU9NmzbF2dmZ\nn376CYDly5cTHBwM6Bc+v7pewdVP9QBNmjQxTFd8NdvGjRu5fPky586dIyYmhrvuuuuGLIMGDWLR\nokWGopSYmEhRUREFBQW4urpia2vL3r17OX36tOE59erVY/369SxbtoxVq1bV6HcTlke6jITZKC4u\nJjAwkLKyMuzs7Jg2bRrPPvssADNnzmTMmDEsW7aMwYMHX7MqmqurK1qtllGjRhluW7t2LcuXL8fe\n3h4PDw9eeeWVWx5bo9FcM5onMjKSGTNm4O/vT6NGjVi6dOlNH3f9CKCbjQhaunQpjz/+OEVFRbRr\n184wXfm//vUvxo8fz2effcbQoUMNzw0JCSEqKorAwEDmzJmDRqPBz8+PkJAQzp49y2uvvYa7uzt/\n/fXXNcd7+OGHSUlJoXv37iiKgqurKxs2bGDy5MkMGzYMPz8/evbsec208RqNBgcHB7Zs2UJYWBiO\njo7cf//9t3ythOWS6a9FnVdUVISfnx/x8fE4OjqqHUeIOku6jESdtmvXLrRaLU899ZQUAyHukLQQ\nhBBCANJCEEIIcYUUBCGEEIAUBCGEEFdIQRBCCAFIQRBCCHGFFAQhhBAA/H8Alc/dnlS5igAAAABJ\nRU5ErkJggg==\n", - "text": [ - "" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@hope.jit\n", - "def f_hope(y, t, P, d, B, G, A):\n", - " dy = np.empty(3)\n", - " dy[0] = P - B*y[0]*y[1] - d*y[0]\n", - " dy[1] = B*y[0]*y[1] + G*y[2] - A*y[0]*y[1]\n", - " dy[2] = d*y[0] + A*y[0]*y[1] - G*y[2]\n", - " return dy\n", - "\n", - "@hope.jit\n", - "def f_opt(y, t, dy, P, d, B, G, A):\n", - " dy[0] = P - B*y[0]*y[1] - d*y[0]\n", - " dy[1] = B*y[0]*y[1] + G*y[2] - A*y[0]*y[1]\n", - " dy[2] = d*y[0] + A*y[0]*y[1] - G*y[2]\n", - " return dy\n", - "\n", - "dy = np.empty(3)\n", - "print \"native python\"\n", - "%timeit odeint(f_nat, y0, t)\n", - "print \"hope\"\n", - "%timeit odeint(f_hope, y0, t, args=(P, d, B, G, A))\n", - "print \"hope without allocation\"\n", - "%timeit odeint(f_opt, y0, t, args=(dy, P, d, B, G, A))" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "native python\n", - "100 loops, best of 3: 4.46 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope\n", - "1000 loops, best of 3: 515 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope without allocation\n", - "1000 loops, best of 3: 470 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 4 - }, + } + ], + "source": [ + "@hope.jit\n", + "def f_hope(y, t, P, d, B, G, A):\n", + " dy = np.empty(3)\n", + " dy[0] = P - B*y[0]*y[1] - d*y[0]\n", + " dy[1] = B*y[0]*y[1] + G*y[2] - A*y[0]*y[1]\n", + " dy[2] = d*y[0] + A*y[0]*y[1] - G*y[2]\n", + " return dy\n", + "\n", + "@hope.jit\n", + "def f_opt(y, t, dy, P, d, B, G, A):\n", + " dy[0] = P - B*y[0]*y[1] - d*y[0]\n", + " dy[1] = B*y[0]*y[1] + G*y[2] - A*y[0]*y[1]\n", + " dy[2] = d*y[0] + A*y[0]*y[1] - G*y[2]\n", + " return dy\n", + "\n", + "dy = np.empty(3)\n", + "print(\"native python\")\n", + "%timeit odeint(f_nat, y0, t)\n", + "print(\"hope\")\n", + "%timeit odeint(f_hope, y0, t, args=(P, d, B, G, A))\n", + "print(\"hope without allocation\")\n", + "%timeit odeint(f_opt, y0, t, args=(dy, P, d, B, G, A))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Approximate expensive functions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### tanh" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": { - "slideshow": { - "slide_type": "slide" - } + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] }, - "source": [ - "Approximate expensive functions" - ] - }, - { - "cell_type": "heading", - "level": 3, "metadata": {}, - "source": [ - "tanh" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def tanhpoly(x):\n", - " a = np.fabs(x)\n", - " b = 1.26175667589988239 + a * (-0.54699348440059470 + a * 2.66559097474027817)\n", - " return (b * x) / (b * a + 1)\n", - "\n", - "x = np.linspace(-10, 10, 10000)\n", - "\n", - "plt.subplot(2, 1,1)\n", - "plt.plot(x, tanhpoly(x), label=\"approx\")\n", - "plt.plot(x, np.tanh(x), label=\"tanh\")\n", - "plt.ylabel('Tanh(x)')\n", - "plt.legend()\n", - "\n", - "plt.subplot(2, 1,2)\n", - "plt.semilogy()\n", - "plt.plot(x, np.fabs(tanhpoly(x)- np.tanh(x)))\n", - "plt.ylabel('Absolute Error')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@hope.jit\n", - "def tanh_hope(x, y):\n", - " y[:] = np.tanh(x)\n", - "\n", - "@hope.jit\n", - "def tanhpoly_hope(x, y):\n", - " a = np.fabs(x)\n", - " b = 1.26175667589988239 + a * (-0.54699348440059470 + a * 2.66559097474027817)\n", - " y[:] = (b * x) / (b * a + 1)\n", - "\n", - "y = np.empty_like(x)\n", - "\n", - "print \"numpy tanh\"\n", - "%timeit tanh_hope(x, y)\n", - "print \"polynomial approximation\"\n", - "%timeit tanhpoly_hope(x, y)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "numpy tanh\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 759 \u00b5s per loop\n", - "polynomial approximation\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 23.8 \u00b5s per loop\n" - ] - } - ], - "prompt_number": 6 - }, + "output_type": "display_data" + } + ], + "source": [ + "def tanhpoly(x):\n", + " a = np.fabs(x)\n", + " b = 1.26175667589988239 + a * (-0.54699348440059470 + a * 2.66559097474027817)\n", + " return (b * x) / (b * a + 1)\n", + "\n", + "x = np.linspace(-10, 10, 10000)\n", + "\n", + "plt.subplot(2, 1,1)\n", + "plt.plot(x, tanhpoly(x), label=\"approx\")\n", + "plt.plot(x, np.tanh(x), label=\"tanh\")\n", + "plt.ylabel('Tanh(x)')\n", + "plt.legend()\n", + "\n", + "plt.subplot(2, 1,2)\n", + "plt.semilogy()\n", + "plt.plot(x, np.fabs(tanhpoly(x)- np.tanh(x)))\n", + "plt.ylabel('Absolute Error')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 3, - "metadata": {}, - "source": [ - "exp" + "name": "stdout", + "output_type": "stream", + "text": [ + "numpy tanh\n", + "1.32 µs ± 541 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "polynomial approximation\n", + "The slowest run took 6.28 times longer than the fastest. This could mean that an intermediate result is being cached.\n", + "1.12 µs ± 1.12 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@hope.jit\n", - "def expapprox(x, y):\n", - " y[:] = hope.exp(x)\n", - " return y\n", - "\n", - "x = np.linspace(-16, 0, 10000)\n", - "y = np.empty_like(x)\n", - "\n", - "plt.subplot(3, 1, 1)\n", - "plt.plot(x, expapprox(x, y), label=\"approx\")\n", - "plt.plot(x, np.exp(x), label=\"exp\")\n", - "plt.ylabel('Exp(x)')\n", - "plt.legend()\n", - "\n", - "plt.subplot(3, 1, 2)\n", - "plt.semilogy()\n", - "plt.plot(x, np.fabs(expapprox(x, y)- np.exp(x)) + np.finfo(np.float64).resolution)\n", - "plt.ylabel('Absolute Error')\n", - "\n", - "plt.subplot(3, 1, 3)\n", - "plt.semilogy()\n", - "plt.plot(x, np.fabs(expapprox(x, y)- np.exp(x)) / np.exp(x) + np.finfo(np.float64).resolution)\n", - "plt.ylabel('Relative Error')\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "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\nYQgEAoGAi/8HnIqwBONccX4AAAAASUVORK5CYII=\n", - "text": [ - "" - ] - } - ], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "@hope.jit\n", - "def exp_hope(x, y):\n", - " y[:] = np.exp(x)\n", - "\n", - "@hope.jit\n", - "def exppow_hope(x, y):\n", - " y[:] = hope.exp(x)\n", - " \n", - "y = np.empty_like(x)\n", - "\n", - "print \"numpy exp\"\n", - "%timeit exp_hope(x, y)\n", - "print \"polynomial exp\"\n", - "%timeit exppow_hope(x, y)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "numpy exp\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 68.9 \u00b5s per loop\n", - "polynomial exp\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 21 \u00b5s per loop\n" - ] - } - ], - "prompt_number": 8 - }, + } + ], + "source": [ + "@hope.jit\n", + "def tanh_hope(x, y):\n", + " y[:] = np.tanh(x)\n", + "\n", + "@hope.jit\n", + "def tanhpoly_hope(x, y):\n", + " a = np.fabs(x)\n", + " b = 1.26175667589988239 + a * (-0.54699348440059470 + a * 2.66559097474027817)\n", + " y[:] = (b * x) / (b * a + 1)\n", + "\n", + "y = np.empty_like(x)\n", + "\n", + "print(\"numpy tanh\")\n", + "%timeit tanh_hope(x, y)\n", + "print(\"polynomial approximation\")\n", + "%timeit tanhpoly_hope(x, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### exp" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": { - "slideshow": { - "slide_type": "slide" - } + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] }, - "source": [ - "Avoid floating point powers" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def native_pow(x, y):\n", - " y[:] = 16.11 - 3./(3. * x**2) + 0.5 *(0.4651 * x**-3 + 43.44) * x**-3 + 4. * x**-4\n", - " \n", - "@hope.jit\n", - "def float_pow(x, y):\n", - " y[:] = 16.11 - 3./(3. * x**2.) + 0.5 *(0.4651 * x**-3. + 43.44) * x**-3. + 4. * x**-4.\n", - "\n", - "@hope.jit\n", - "def int_pow(x, y):\n", - " y[:] = 16.11 - 3./(3. * x**2) + 0.5 *(0.4651 * x**-3 + 43.44) * x**-3 + 4. * x**-4\n", - "\n", - "x = np.linspace(-10, 10, 10000)\n", - "y = np.empty_like(x)\n", - "\n", - "print \"native python\"\n", - "%timeit native_pow(x, y)\n", - "print \"hope float power\"\n", - "%timeit float_pow(x, y)\n", - "print \"hope integer power\"\n", - "%timeit int_pow(x, y)" - ], - "language": "python", "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "native python\n", - "1000 loops, best of 3: 1.14 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope float power\n", - "Integer exponent as flaot: x.d[:x@0]**(-2.0)" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "Integer exponent as flaot: x.d[:x@0]**(-4.0)\n", - "Integer exponent as flaot: x.d[:x@0]**(-6.0)\n", - "Integer exponent as flaot: x.d[:x@0]**(-3.0)\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 1.43 ms per loop\n", - "hope integer power\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 81.1 \u00b5s per loop\n" - ] - } - ], - "prompt_number": 9 - }, + "output_type": "display_data" + } + ], + "source": [ + "@hope.jit\n", + "def expapprox(x, y):\n", + " y[:] = hope.exp(x)\n", + " return y\n", + "\n", + "x = np.linspace(-16, 0, 10000)\n", + "y = np.empty_like(x)\n", + "\n", + "plt.subplot(3, 1, 1)\n", + "plt.plot(x, expapprox(x, y), label=\"approx\")\n", + "plt.plot(x, np.exp(x), label=\"exp\")\n", + "plt.ylabel('Exp(x)')\n", + "plt.legend()\n", + "\n", + "plt.subplot(3, 1, 2)\n", + "plt.semilogy()\n", + "plt.plot(x, np.fabs(expapprox(x, y)- np.exp(x)) + np.finfo(np.float64).resolution)\n", + "plt.ylabel('Absolute Error')\n", + "\n", + "plt.subplot(3, 1, 3)\n", + "plt.semilogy()\n", + "plt.plot(x, np.fabs(expapprox(x, y)- np.exp(x)) / np.exp(x) + np.finfo(np.float64).resolution)\n", + "plt.ylabel('Relative Error')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Improve interpolation" + "ename": "SyntaxError", + "evalue": "Missing parentheses in call to 'print' (, line 11)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m11\u001b[0m\n\u001b[0;31m print \"numpy exp\"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m Missing parentheses in call to 'print'\n" ] - }, + } + ], + "source": [ + "@hope.jit\n", + "def exp_hope(x, y):\n", + " y[:] = np.exp(x)\n", + "\n", + "@hope.jit\n", + "def exppow_hope(x, y):\n", + " y[:] = hope.exp(x)\n", + " \n", + "y = np.empty_like(x)\n", + "\n", + "print(\"numpy exp\")\n", + "%timeit exp_hope(x, y)\n", + "print(\"polynomial exp\")\n", + "%timeit exppow_hope(x, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Avoid floating point powers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def native_pow(x, y):\n", + " y[:] = 16.11 - 3./(3. * x**2) + 0.5 *(0.4651 * x**-3 + 43.44) * x**-3 + 4. * x**-4\n", + " \n", + "@hope.jit\n", + "def float_pow(x, y):\n", + " y[:] = 16.11 - 3./(3. * x**2.) + 0.5 *(0.4651 * x**-3. + 43.44) * x**-3. + 4. * x**-4.\n", + "\n", + "@hope.jit\n", + "def int_pow(x, y):\n", + " y[:] = 16.11 - 3./(3. * x**2) + 0.5 *(0.4651 * x**-3 + 43.44) * x**-3 + 4. * x**-4\n", + "\n", + "x = np.linspace(-10, 10, 10000)\n", + "y = np.empty_like(x)\n", + "\n", + "print(\"native python\")\n", + "%timeit native_pow(x, y)\n", + "print(\"hope float power\")\n", + "%timeit float_pow(x, y)\n", + "print(\"hope integer power\")\n", + "%timeit int_pow(x, y)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Improve interpolation" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "X = np.empty(1100)\n", - "X[:1024] = np.linspace(-1., 1., 1024)\n", - "X[1024:] = X[1023] + X[1:77] - X[0]\n", - "SN = np.sin(X)\n", - "CN = np.cos(X)\n", - "\n", - "@hope.jit\n", - "def approx(x, sn, cn, X, SN, CN):\n", - " for i in range(100):\n", - " sn[i] = np.interp(x[i], X, SN)\n", - " cn[i] = np.interp(x[i], X, CN)\n", - "\n", - "@hope.jit\n", - "def approx_opt(x, sn, cn, X, SN, CN):\n", - " for i in range(100):\n", - " f = (x[i] - X[0]) / (X[1024] - X[0]) * 1024.\n", - " g = np.floor(f)\n", - " j = np.int_(g)\n", - " a = f - g\n", - " sn[i] = (1 - a) * SN[j] + a * SN[j + 1]\n", - " cn[i] = (1 - a) * CN[j] + a * CN[j + 1]\n", - "\n", - "x = 2. * random_sample(100) - 1\n", - "sn = np.empty_like(x)\n", - "cn = np.empty_like(x)\n", - "\n", - "%timeit approx(x, sn, cn, X, SN, CN)\n", - "%timeit approx_opt(x, sn, cn, X, SN, CN)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 10 \u00b5s per loop\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 954 ns per loop\n" - ] - } - ], - "prompt_number": 10 + "name": "stdout", + "output_type": "stream", + "text": [ + "9.79 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "The slowest run took 6.76 times longer than the fastest. This could mean that an intermediate result is being cached.\n", + "1.91 µs ± 1.99 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" + ] } ], - "metadata": {} + "source": [ + "X = np.empty(1100)\n", + "X[:1024] = np.linspace(-1., 1., 1024)\n", + "X[1024:] = X[1023] + X[1:77] - X[0]\n", + "SN = np.sin(X)\n", + "CN = np.cos(X)\n", + "\n", + "@hope.jit\n", + "def approx(x, sn, cn, X, SN, CN):\n", + " for i in range(100):\n", + " sn[i] = np.interp(x[i], X, SN)\n", + " cn[i] = np.interp(x[i], X, CN)\n", + "\n", + "@hope.jit\n", + "def approx_opt(x, sn, cn, X, SN, CN):\n", + " for i in range(100):\n", + " f = (x[i] - X[0]) / (X[1024] - X[0]) * 1024.\n", + " g = np.floor(f)\n", + " j = np.int_(g)\n", + " a = f - g\n", + " sn[i] = (1 - a) * SN[j] + a * SN[j + 1]\n", + " cn[i] = (1 - a) * CN[j] + a * CN[j + 1]\n", + "\n", + "x = 2. * random_sample(100) - 1\n", + "sn = np.empty_like(x)\n", + "cn = np.empty_like(x)\n", + "\n", + "%timeit approx(x, sn, cn, X, SN, CN)\n", + "%timeit approx_opt(x, sn, cn, X, SN, CN)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" } - ] -} \ No newline at end of file + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/compile b/benchmarks/compile new file mode 100644 index 0000000..22e8c02 --- /dev/null +++ b/benchmarks/compile @@ -0,0 +1 @@ +clang++ -bundle -undefined dynamic_lookup fib.o build/temp.macosx-10.11-x86_64-2.7/recfast4py/cosmology.Recfast.o build/temp.macosx-10.11-x86_64-2.7/recfast4py/evalode.Recfast.o build/temp.macosx-10.11-x86_64-2.7/recfast4py/recombination.Recfast.o build/temp.macosx-10.11-x86_64-2.7/recfast4py/ODE_solver.Recfast.o build/temp.macosx-10.11-x86_64-2.7/recfast4py/DM_annihilation.Recfast.o build/temp.macosx-10.11-x86_64-2.7/recfast4py/Rec_corrs_CT.Recfast.o -o build/lib.macosx-10.11-x86_64-2.7/recfast4py/_recfast.so diff --git a/benchmarks/fibonacci.ipynb b/benchmarks/fibonacci.ipynb index 9a09e74..52e3542 100644 --- a/benchmarks/fibonacci.ipynb +++ b/benchmarks/fibonacci.ipynb @@ -1,208 +1,208 @@ { - "metadata": { - "name": "", - "signature": "sha256:c2e8018cf3530fa66b1f12e3044c71d39d6f7c1954acb15ff475eefbef500867" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from util import perf_comp_data" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def fib(n):\n", + " if n < 2:\n", + " return n\n", + " return fib(n - 1) + fib(n - 2)\n", + "\n", + "assert fib(20) == 6765" + ] + }, { - "cells": [ + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from hope import jit\n", + "\n", + "hope_fib = jit(fib)\n", + "\n", + "assert hope_fib(20) == 6765" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from numba import jit\n", + "\n", + "numba_fib = jit(fib)\n", + "assert numba_fib(20) == 6765" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from util import perf_comp_data" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 1 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "python\n", + "3.13 ms ± 139 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "hope 1\n", + "39.4 µs ± 617 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "numba\n", + "3.07 ms ± 40.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "print(\"python\")\n", + "%timeit fib(20)\n", + "print(\"hope 1\")\n", + "%timeit hope_fib(20)\n", + "print(\"numba\")\n", + "%timeit numba_fib(20)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ + "name": "stdout", + "output_type": "stream", + "text": [ + "function: hope_fib , av. time sec: 0.00005121, min. time sec: 0.00004093, relative: 1.0\n", + "function: numba_fib , av. time sec: 0.00359036, min. time sec: 0.00320426, relative: 70.1\n", + "function: fib , av. time sec: 0.00361408, min. time sec: 0.00353485, relative: 70.6\n" + ] + } + ], + "source": [ + "n=20\n", + "perf_comp_data([\"fib\", \"hope_fib\", \"numba_fib\"], 3*[\"n\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fib (int64,)\n", + "--------------------------------------------------------------------------------\n", + "# File: \n", + "# --- LINE 1 --- \n", + "# label 0\n", + "# del $const0.2\n", + "\n", "def fib(n):\n", + "\n", + " # --- LINE 2 --- \n", + " # n = arg(0, name=n) :: pyobject\n", + " # $const0.2 = const(int, 2) :: pyobject\n", + " # $0.3 = n < $const0.2 :: pyobject\n", + " # branch $0.3, 12, 16\n", + " # label 12\n", + " # del $0.3\n", + " # del n\n", + "\n", " if n < 2:\n", + "\n", + " # --- LINE 3 --- \n", + " # $12.2 = cast(value=n) :: pyobject\n", + " # return $12.2\n", + " # label 16\n", + " # del $0.3\n", + " # del $const16.3\n", + " # del $16.4\n", + " # del $16.1\n", + " # del n\n", + " # del $const16.8\n", + " # del $16.9\n", + " # del $16.6\n", + " # del $16.5\n", + " # del $16.10\n", + " # del $16.11\n", + "\n", " return n\n", - " return fib(n - 1) + fib(n - 2)\n", "\n", - "assert fib(20) == 6765" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from hope import jit\n", + " # --- LINE 4 --- \n", + " # $16.1 = global(fib: ) :: pyobject\n", + " # $const16.3 = const(int, 1) :: pyobject\n", + " # $16.4 = n - $const16.3 :: pyobject\n", + " # $16.5 = call $16.1($16.4, kws=[], args=[Var($16.4, (4))], func=$16.1, vararg=None) :: pyobject\n", + " # $16.6 = global(fib: ) :: pyobject\n", + " # $const16.8 = const(int, 2) :: pyobject\n", + " # $16.9 = n - $const16.8 :: pyobject\n", + " # $16.10 = call $16.6($16.9, kws=[], args=[Var($16.9, (4))], func=$16.6, vararg=None) :: pyobject\n", + " # $16.11 = $16.5 + $16.10 :: pyobject\n", + " # $16.12 = cast(value=$16.11) :: pyobject\n", + " # return $16.12\n", "\n", - "hope_fib = jit(fib)\n", + " return fib(n - 1) + fib(n - 2)\n", "\n", - "assert hope_fib(20) == 6765" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from numba import jit\n", "\n", - "numba_fib = jit(fib)\n", - "assert numba_fib(20) == 6765" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print \"python\"\n", - "%timeit fib(20)\n", - "print \"hope 1\"\n", - "%timeit hope_fib(20)\n", - "print \"numba\"\n", - "%timeit numba_fib(20)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "python\n", - "100 loops, best of 3: 2.59 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope 1\n", - "10000 loops, best of 3: 42 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numba\n", - "100 loops, best of 3: 2.67 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "n=20\n", - "perf_comp_data([\"fib\", \"hope_fib\", \"numba_fib\"], 3*[\"n\"])" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: hope_fib , av. time sec: 0.00005205, relative: 1.0\n", - "function: fib , av. time sec: 0.00290926, relative: 55.9\n", - "function: numba_fib , av. time sec: 0.00306726, relative: 58.9\n" - ] - } - ], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "numba_fib.inspect_types()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "fib (int64,)\n", - "--------------------------------------------------------------------------------\n", - "# File: \n", - "# --- LINE 1 --- \n", - "\n", - "def fib(n):\n", - "\n", - " # --- LINE 2 --- \n", - " # label 0\n", - " # n.1 = n :: pyobject\n", - " # $const0.2 = const(, 2) :: pyobject\n", - " # $0.3 = n.1 < $const0.2 :: pyobject\n", - " # branch $0.3, 12, 16\n", - "\n", - " if n < 2:\n", - "\n", - " # --- LINE 3 --- \n", - " # label 12\n", - " # return n.1\n", - "\n", - " return n\n", - "\n", - " # --- LINE 4 --- \n", - " # label 16\n", - " # $16.1 = global(fib: ) :: pyobject\n", - " # $const16.3 = const(, 1) :: pyobject\n", - " # $16.4 = n.1 - $const16.3 :: pyobject\n", - " # $16.5 = call $16.1($16.4, ) :: pyobject\n", - " # $16.6 = global(fib: ) :: pyobject\n", - " # $const16.8 = const(, 2) :: pyobject\n", - " # $16.9 = n.1 - $const16.8 :: pyobject\n", - " # $16.10 = call $16.6($16.9, ) :: pyobject\n", - " # $16.11 = $16.5 + $16.10 :: pyobject\n", - " # return $16.11\n", - "\n", - " return fib(n - 1) + fib(n - 2)\n", - "\n", - "\n", - "================================================================================\n" - ] - } - ], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] + "================================================================================\n" + ] } ], - "metadata": {} + "source": [ + "numba_fib.inspect_types()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } - ] -} \ No newline at end of file + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/julialang.org.ipynb b/benchmarks/julialang.org.ipynb index 7459d05..04fef7c 100644 --- a/benchmarks/julialang.org.ipynb +++ b/benchmarks/julialang.org.ipynb @@ -1,813 +1,639 @@ { - "metadata": { - "name": "", - "signature": "sha256:2dc0f66f43617ca29e3f9e2e223da552ebd0f852686cd4d0a4f32aa41ec4f354" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import hope\n", - "hope.config.optimize = True\n", - "hope.config.verbose = True\n", - "hope.config.keeptemp = True\n", - "import numba\n", - "import numpy as np\n", - "from util import perf_comp_data\n", - "from native_util import load\n", - "%load_ext cythonmagic\n", - "%load_ext version_information\n", - "%version_information numpy, Cython, numba, hope" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "
SoftwareVersion
Python2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
IPython1.1.0
OSDarwin 13.4.0 x86_64 i386 64bit
numpy1.8.1
Cython0.20.2
numbatag: 0.13.3
hope0.3.0
Thu Dec 04 11:18:15 2014 CET
" - ], - "json": [ - "{\"Software versions\": [{\"version\": \"2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\", \"module\": \"Python\"}, {\"version\": \"1.1.0\", \"module\": \"IPython\"}, {\"version\": \"Darwin 13.4.0 x86_64 i386 64bit\", \"module\": \"OS\"}, {\"version\": \"1.8.1\", \"module\": \"numpy\"}, {\"version\": \"0.20.2\", \"module\": \"Cython\"}, {\"version\": \"tag: 0.13.3\", \"module\": \"numba\"}, {\"version\": \"0.3.0\", \"module\": \"hope\"}]}" - ], - "latex": [ - "\\begin{tabular}{|l|l|}\\hline\n", - "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", - "Python & 2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] \\\\ \\hline\n", - "IPython & 1.1.0 \\\\ \\hline\n", - "OS & Darwin 13.4.0 x86\\_64 i386 64bit \\\\ \\hline\n", - "numpy & 1.8.1 \\\\ \\hline\n", - "Cython & 0.20.2 \\\\ \\hline\n", - "numba & tag: 0.13.3 \\\\ \\hline\n", - "hope & 0.3.0 \\\\ \\hline\n", - "\\hline \\multicolumn{2}{|l|}{Thu Dec 04 11:18:15 2014 CET} \\\\ \\hline\n", - "\\end{tabular}\n" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "Software versions\n", - "Python 2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\n", - "IPython 1.1.0\n", - "OS Darwin 13.4.0 x86_64 i386 64bit\n", - "numpy 1.8.1\n", - "Cython 0.20.2\n", - "numba tag: 0.13.3\n", - "hope 0.3.0\n", - "Thu Dec 04 11:18:15 2014 CET" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "heading", - "level": 1, - "metadata": {}, - "source": [ - "fibonacci" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def fib(n):\n", - " if n<2:\n", - " return n\n", - " return fib(n-1)+fib(n-2)\n", - "hope_fib = hope.jit(fib)\n", - "numba_fib = numba.jit(fib, nopython=False)\n", - "\n", - "native_fib_mod = load(\"fib\")\n", - "native_fib = native_fib_mod.run \n", - "\n", - "n=20\n", - "assert fib(20) == 6765\n", - "assert hope_fib(20) == 6765\n", - "assert numba_fib(20) == 6765\n", - "assert native_fib(20) == 6765" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'fib' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/workspace/virtualenvs/hope_benchmarks/lib/python2.7/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/fib.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db48 ./src/fib.o -o ./fib.so\n", - "\n", - "fib(int64 n)\n", - "\tif (n.J < 2.J) {\n", - "\t\treturn n.J\n", - "\t}\n", - "\treturn (fib((n.J - 1.J)) + fib((n.J - 2.J)))\n", - "\n", - "Compiling following functions:" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "fib(int64 n)\n" + "data": { + "application/json": { + "Software versions": [ + { + "module": "Python", + "version": "3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]" + }, + { + "module": "IPython", + "version": "6.1.0" + }, + { + "module": "OS", + "version": "Darwin 15.6.0 x86_64 i386 64bit" + }, + { + "module": "numpy", + "version": "1.13.1" + }, + { + "module": "Cython", + "version": "0.26" + }, + { + "module": "numba", + "version": "0.34.0" + }, + { + "module": "hope", + "version": "0.6.1" + } ] }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'fib_181039868ed022600dc3388e38604df736dff187257d5d6ae4c4d3ea_0' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/workspace/virtualenvs/hope_benchmarks/lib/python2.7/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: /var/folders/k_/ttz9cd4d3kj2kbh3lvtn6tkm0000gn/T/hopeDXfz9_/fib_181039868ed022600dc3388e38604df736dff187257d5d6ae4c4d3ea_0.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db48 /var/folders/k_/ttz9cd4d3kj2kbh3lvtn6tkm0000gn/T/hopeDXfz9_/fib_181039868ed022600dc3388e38604df736dff187257d5d6ae4c4d3ea_0.o -o /var/folders/k_/ttz9cd4d3kj2kbh3lvtn6tkm0000gn/T/hopeDXfz9_/fib_181039868ed022600dc3388e38604df736dff187257d5d6ae4c4d3ea_0.so\n", - "\n" - ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "\n", - "cimport cython\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "cpdef int cython_fib(int n):\n", - " if n<2:\n", - " return n\n", - " return cython_fib(n-1)+cython_fib(n-2)\n", - "\n", - "assert cython_fib(20) == 6765\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "building '_cython_magic_d4ac66e2963d3320a31dcc65e2809bf2' extension\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "compile options: '-I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "clang: /Users/jakeret/.ipython/cython/_cython_magic_d4ac66e2963d3320a31dcc65e2809bf2.c\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "/usr/bin/clang -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db48 /Users/jakeret/.ipython/cython/Users/jakeret/.ipython/cython/_cython_magic_d4ac66e2963d3320a31dcc65e2809bf2.o -o /Users/jakeret/.ipython/cython/_cython_magic_d4ac66e2963d3320a31dcc65e2809bf2.so\n" - ] - } - ], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%timeit fib(20)\n", - "%timeit hope_fib(20)\n", - "%timeit numba_fib(20)\n", - "%timeit cython_fib(20)\n", - "%timeit native_fib(20)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "100 loops, best of 3: 2.59 ms per loop\n", - "10000 loops, best of 3: 40.6 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "100 loops, best of 3: 2.55 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10000 loops, best of 3: 42.5 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10000 loops, best of 3: 41.4 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "perf_comp_data([\"fib\", \"hope_fib\", \"numba_fib\", \"cython_fib\", \"native_fib\"],\n", - " 5*[\"n\"])" - ], - "language": "python", + "text/html": [ + "
SoftwareVersion
Python3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
IPython6.1.0
OSDarwin 15.6.0 x86_64 i386 64bit
numpy1.13.1
Cython0.26
numba0.34.0
hope0.6.1
Tue Aug 29 17:15:40 2017 CEST
" + ], + "text/latex": [ + "\\begin{tabular}{|l|l|}\\hline\n", + "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", + "Python & 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] \\\\ \\hline\n", + "IPython & 6.1.0 \\\\ \\hline\n", + "OS & Darwin 15.6.0 x86\\_64 i386 64bit \\\\ \\hline\n", + "numpy & 1.13.1 \\\\ \\hline\n", + "Cython & 0.26 \\\\ \\hline\n", + "numba & 0.34.0 \\\\ \\hline\n", + "hope & 0.6.1 \\\\ \\hline\n", + "\\hline \\multicolumn{2}{|l|}{Tue Aug 29 17:15:40 2017 CEST} \\\\ \\hline\n", + "\\end{tabular}\n" + ], + "text/plain": [ + "Software versions\n", + "Python 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n", + "IPython 6.1.0\n", + "OS Darwin 15.6.0 x86_64 i386 64bit\n", + "numpy 1.13.1\n", + "Cython 0.26\n", + "numba 0.34.0\n", + "hope 0.6.1\n", + "Tue Aug 29 17:15:40 2017 CEST" + ] + }, + "execution_count": 1, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: native_fib , av. time sec: 0.00003982, min. time sec: 0.00003886, relative: 1.0\n", - "function: hope_fib , av. time sec: 0.00004315, min. time sec: 0.00003815, relative: 1.1\n", - "function: cython_fib , av. time sec: 0.00004911, min. time sec: 0.00004101, relative: 1.2\n", - "function: numba_fib , av. time sec: 0.00260401, min. time sec: 0.00255513, relative: 65.4\n", - "function: fib , av. time sec: 0.00291204, min. time sec: 0.00247192, relative: 73.1\n" - ] - } - ], - "prompt_number": 7 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import hope\n", + "hope.config.optimize = True\n", + "hope.config.verbose = True\n", + "hope.config.keeptemp = True\n", + "hope.config.prefix = \"hope\"\n", + "import numba\n", + "import numpy as np\n", + "from util import perf_comp_data\n", + "from native_util import load\n", + "%load_ext Cython\n", + "%load_ext version_information\n", + "%version_information numpy, Cython, numba, hope" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# fibonacci" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 1, - "metadata": {}, - "source": [ - "quicksort" + "name": "stdout", + "output_type": "stream", + "text": [ + "running build_ext\n", + "\n" ] - }, + } + ], + "source": [ + "def fib(n):\n", + " if n<2:\n", + " return n\n", + " return fib(n-1)+fib(n-2)\n", + "hope_fib = hope.jit(fib)\n", + "numba_fib = numba.jit(fib, nopython=False)\n", + "\n", + "native_fib_mod = load(\"fib\")\n", + "native_fib = native_fib_mod.run \n", + "\n", + "n=20\n", + "assert fib(20) == 6765\n", + "assert hope_fib(20) == 6765\n", + "assert numba_fib(20) == 6765\n", + "assert native_fib(20) == 6765" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "%%cython\n", + "\n", + "cimport cython\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "cpdef int cython_fib(int n):\n", + " if n<2:\n", + " return n\n", + " return cython_fib(n-1)+cython_fib(n-2)\n", + "\n", + "assert cython_fib(20) == 6765\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "def qsort_kernel(a, lo, hi):\n", - " i = lo\n", - " j = hi\n", - " if False: return a\n", - " while i < hi:\n", - " pivot = a[(lo+hi) // 2]\n", - " while i <= j:\n", - " while a[i] < pivot:\n", - " i += 1\n", - " while a[j] > pivot:\n", - " j -= 1\n", - " if i <= j:\n", - " tmp = a[i]\n", - " a[i] = a[j]\n", - " a[j] = tmp\n", - " i += 1\n", - " j -= 1\n", - " if lo < j:\n", - " qsort_kernel(a, lo, j)\n", - " lo = i\n", - " j = hi\n", - " return a\n", - "\n", - "hope_qsort_kernel = hope.jit(qsort_kernel)\n", - "numba_qsort_kernel = numba.jit(qsort_kernel)\n", - "\n", - "native_qsort_kernel_mod = load(\"qsort_kernel\")\n", - "native_qsort_kernel = native_qsort_kernel_mod.run\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'qsort_kernel' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/qsort_kernel.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/qsort_kernel.o -o ./qsort_kernel.so\n", - "\n" - ] - } - ], - "prompt_number": 8 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "3.11 ms ± 32.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "39.5 µs ± 707 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "3.07 ms ± 30.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "39.5 µs ± 571 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "39.6 µs ± 522 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" + ] + } + ], + "source": [ + "%timeit fib(20)\n", + "%timeit hope_fib(20)\n", + "%timeit numba_fib(20)\n", + "%timeit cython_fib(20)\n", + "%timeit native_fib(20)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "def numpy_qsort_kernel(a, lo, hi):\n", - " np.sort(a)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 16 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "function: native_fib , av. time sec: 0.00003945, min. time sec: 0.00003941, relative: 1.0\n", + "function: cython_fib , av. time sec: 0.00003969, min. time sec: 0.00003967, relative: 1.0\n", + "function: hope_fib , av. time sec: 0.00004080, min. time sec: 0.00004075, relative: 1.0\n", + "function: numba_fib , av. time sec: 0.00341285, min. time sec: 0.00320110, relative: 86.5\n", + "function: fib , av. time sec: 0.00344686, min. time sec: 0.00311820, relative: 87.4\n" + ] + } + ], + "source": [ + "perf_comp_data([\"fib\", \"hope_fib\", \"numba_fib\", \"cython_fib\", \"native_fib\"],\n", + " 5*[\"n\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# quicksort" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "running build_ext\n", + "building 'qsort_kernel' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "cimport cython\n", - "import numpy as np\n", - "cimport numpy as np\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def cython_qsort_kernel(np.ndarray[np.double_t, ndim=1] a, int lo, int hi):\n", - " cdef int i = lo\n", - " cdef int j = hi\n", - " cdef double pivot = 0\n", - " cdef double tmp = 0.0\n", - " if False: return a\n", - " while i < hi:\n", - " pivot = a[(lo+hi) // 2]\n", - " while i <= j:\n", - " while a[i] < pivot:\n", - " i += 1\n", - " while a[j] > pivot:\n", - " j -= 1\n", - " if i <= j:\n", - " tmp = a[i]\n", - " a[i] = a[j]\n", - " a[j] = tmp\n", - " i += 1\n", - " j -= 1\n", - " if lo < j:\n", - " cython_qsort_kernel(a, lo, j)\n", - " lo = i\n", - " j = hi\n", - " return a\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", "\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 17 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "lst = np.random.random(5000)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 18 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "psorted = qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "hsorted = hope_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "#nsorted = numba_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "csorted = cython_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "nasorted = native_qsort_kernel(lst.copy(), 0, len(lst)-1)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 19 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "assert np.all(psorted[:-1] <= psorted[1:])\n", - "#assert np.all(hope_qsort_kernel[:-1] <= hope_qsort_kernel[1:])\n", - "#assert np.all(numba_qsort_kernel[:-1] <= numba_qsort_kernel[1:])\n", - "#assert np.all(cython_qsort_kernel[:-1] <= cython_qsort_kernel[1:])\n", - "\n", - "%timeit qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "%timeit hope_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "#%timeit numba_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "%timeit cython_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "%timeit native_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", - "%timeit np.sort(lst.copy())" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "10 loops, best of 3: 22.4 ms per loop\n", - "1000 loops, best of 3: 334 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1000 loops, best of 3: 1.4 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1000 loops, best of 3: 303 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1000 loops, best of 3: 248 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 20 - }, + ] + } + ], + "source": [ + "def qsort_kernel(a, lo, hi):\n", + " i = lo\n", + " j = hi\n", + " if False: return a\n", + " while i < hi:\n", + " pivot = a[(lo+hi) // 2]\n", + " while i <= j:\n", + " while a[i] < pivot:\n", + " i += 1\n", + " while a[j] > pivot:\n", + " j -= 1\n", + " if i <= j:\n", + " tmp = a[i]\n", + " a[i] = a[j]\n", + " a[j] = tmp\n", + " i += 1\n", + " j -= 1\n", + " if lo < j:\n", + " qsort_kernel(a, lo, j)\n", + " lo = i\n", + " j = hi\n", + " return a\n", + "\n", + "hope_qsort_kernel = hope.jit(qsort_kernel)\n", + "numba_qsort_kernel = numba.jit(qsort_kernel)\n", + "\n", + "native_qsort_kernel_mod = load(\"qsort_kernel\")\n", + "native_qsort_kernel = native_qsort_kernel_mod.run\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def numpy_qsort_kernel(a, lo, hi):\n", + " np.sort(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "a = lst.copy()\n", - "\n", - "lo = 0\n", - "hi = len(lst)-1\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "building '_cython_magic_c4e853c051d00b69b625b262d253da82' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "perf_comp_data([\"hope_qsort_kernel\", \n", - " \"qsort_kernel\", \n", - " #\"numpy_qsort_kernel\", \n", - " \"cython_qsort_kernel\", \n", - " \"native_qsort_kernel\"],\n", - " 5*[\"a, lo, hi\"], rep=100, extra_setup=\"from __main__ import lst;a = lst.copy()\")" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: native_qsort_kernel , av. time sec: 0.00029302, min. time sec: 0.00029182, relative: 1.0\n", - "function: hope_qsort_kernel , av. time sec: 0.00033617, min. time sec: 0.00033379, relative: 1.1\n", - "function: cython_qsort_kernel , av. time sec: 0.00143504, min. time sec: 0.00140619, relative: 4.9\n", - "function: qsort_kernel , av. time sec: 0.02197444, min. time sec: 0.02172208, relative: 75.0\n" - ] - } - ], - "prompt_number": 21 - }, - { - "cell_type": "heading", - "level": 1, - "metadata": {}, - "source": [ - "pi sum" + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "clang: /Users/uweschmitt/.ipython/cython/_cython_magic_c4e853c051d00b69b625b262d253da82.c\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_c4e853c051d00b69b625b262d253da82.c:495:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_c4e853c051d00b69b625b262d253da82.c:495:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "/usr/bin/clang -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /Users/uweschmitt/.ipython/cython/Users/uweschmitt/.ipython/cython/_cython_magic_c4e853c051d00b69b625b262d253da82.o -o /Users/uweschmitt/.ipython/cython/_cython_magic_c4e853c051d00b69b625b262d253da82.cpython-35m-darwin.so\n" ] - }, + } + ], + "source": [ + "%%cython\n", + "\n", + "cimport cython\n", + "import numpy as np\n", + "cimport numpy as np\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "cdef _cython_qsort_kernel(np.double_t * a, int lo, int hi):\n", + " cdef int i = lo\n", + " cdef int j = hi\n", + " cdef double pivot = 0\n", + " cdef double tmp = 0.0\n", + " if False: return a\n", + " while i < hi:\n", + " pivot = a[(lo+hi) // 2]\n", + " while i <= j:\n", + " while a[i] < pivot:\n", + " i += 1\n", + " while a[j] > pivot:\n", + " j -= 1\n", + " if i <= j:\n", + " tmp = a[i]\n", + " a[i] = a[j]\n", + " a[j] = tmp\n", + " i += 1\n", + " j -= 1\n", + " if lo < j:\n", + " _cython_qsort_kernel(a, lo, j)\n", + " lo = i\n", + " j = hi\n", + "\n", + "def cython_qsort_kernel(np.ndarray[np.double_t, ndim=1] a, int lo, int hi):\n", + " _cython_qsort_kernel( a.data, lo, hi)\n", + " return a" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "lst = np.random.random(5000)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "psorted = qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "hsorted = hope_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "#nsorted = numba_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "csorted = cython_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "nasorted = native_qsort_kernel(lst.copy(), 0, len(lst)-1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "def pisum():\n", - " for j in range(1, 501):\n", - " sum = 0.0\n", - " f = 0.0\n", - " for k in range(1, 10001):\n", - " sum += 1.0/(k*k)\n", - " return sum\n", - "def pisum_opt():\n", - " for j in range(1, 501):\n", - " sum = 0.0\n", - " f = 0.0\n", - " for k in range(1, 10001):\n", - " f += 1.\n", - " sum += 1.0/(f*f)\n", - " return sum\n", - "\n", - "hope_pisum = hope.jit(pisum)\n", - "hope_pisum_opt = hope.jit(pisum_opt)\n", - "\n", - "numba_pisum = numba.jit(pisum, nopython=True)\n", - "numba_pisum_opt = numba.jit(pisum_opt, nopython=True)\n", - "\n", - "native_pisum_mod = load(\"pisum\")\n", - "native_pisum = native_pisum_mod.run\n", - "\n", - "native_pisum_opt_mod = load(\"pisum_opt\")\n", - "native_pisum_opt = native_pisum_opt_mod.run\n", - "\n", - "\n", - "assert abs(pisum()-1.644834071848065) < 1e-6\n", - "assert abs(hope_pisum()-1.644834071848065) < 1e-6\n", - "assert abs(hope_pisum_opt()-1.644834071848065) < 1e-6\n", - "assert abs(numba_pisum()-1.644834071848065) < 1e-6\n", - "assert abs(native_pisum()-1.644834071848065) < 1e-6\n", - "assert abs(native_pisum_opt()-1.644834071848065) < 1e-6\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'pisum' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/pisum.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/pisum.o -o ./pisum.so\n", - "\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'pisum_opt' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/pisum_opt.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/pisum_opt.o -o ./pisum_opt.so\n", - "\n" - ] - } - ], - "prompt_number": 23 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "22.9 ms ± 785 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "349 µs ± 3.85 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "332 µs ± 8.69 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "313 µs ± 8.87 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "242 µs ± 15.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" + ] + } + ], + "source": [ + "assert np.all(psorted[:-1] <= psorted[1:])\n", + "#assert np.all(hope_qsort_kernel[:-1] <= hope_qsort_kernel[1:])\n", + "#assert np.all(numba_qsort_kernel[:-1] <= numba_qsort_kernel[1:])\n", + "#assert np.all(cython_qsort_kernel[:-1] <= cython_qsort_kernel[1:])\n", + "\n", + "%timeit qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "%timeit hope_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "#%timeit numba_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "%timeit cython_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "%timeit native_qsort_kernel(lst.copy(), 0, len(lst)-1)\n", + "%timeit np.sort(lst.copy())" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load_ext cythonmagic\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "The cythonmagic extension is already loaded. To reload it, use:\n", - " %reload_ext cythonmagic\n" - ] - } - ], - "prompt_number": 24 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "function: native_qsort_kernel , av. time sec: 0.00029402, min. time sec: 0.00029235, relative: 1.0\n", + "function: cython_qsort_kernel , av. time sec: 0.00031540, min. time sec: 0.00031303, relative: 1.1\n", + "function: hope_qsort_kernel , av. time sec: 0.00035815, min. time sec: 0.00033481, relative: 1.2\n", + "function: qsort_kernel , av. time sec: 0.02226692, min. time sec: 0.02194059, relative: 75.7\n" + ] + } + ], + "source": [ + "a = lst.copy()\n", + "\n", + "lo = 0\n", + "hi = len(lst)-1\n", + "\n", + "perf_comp_data([\"hope_qsort_kernel\", \n", + " \"qsort_kernel\", \n", + " #\"numpy_qsort_kernel\", \n", + " \"cython_qsort_kernel\", \n", + " \"native_qsort_kernel\"],\n", + " 5*[\"a, lo, hi\"], rep=100, extra_setup=\"from __main__ import lst;a = lst.copy()\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# pi sum" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "\n", - "cimport cython\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "@cython.locals(f=float)\n", - "def cython_pisum():\n", - " cdef double sum = 0.0\n", - " for j in range(1, 501):\n", - " sum = 0.0\n", - " f = 0.0\n", - " for k in range(1, 10001):\n", - " sum += 1.0/(k*k)\n", - " return sum\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "running build_ext\n", + "building 'pisum' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "@cython.locals(f=float)\n", - "def cython_pisum_opt():\n", - " cdef double sum = 0.0\n", - " for j in range(1, 501):\n", - " sum = 0.0\n", - " f = 0.0\n", - " for k in range(1, 10001):\n", - " f += 1.\n", - " sum += 1.0/(f*f)\n", - " return sum\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", "\n", + "running build_ext\n", + "building 'pisum_opt' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "assert abs(cython_pisum()-1.644834071848065) < 1e-6\n", - "assert abs(cython_pisum_opt()-1.644834071848065) < 1e-6" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 25 + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "\n" + ] }, { - "cell_type": "code", - "collapsed": false, - "input": [ - "%timeit pisum()\n", - "%timeit pisum_opt()\n", - "%timeit hope_pisum()\n", - "%timeit hope_pisum_opt()\n", - "%timeit numba_pisum()\n", - "%timeit numba_pisum_opt()\n", - "%timeit cython_pisum()\n", - "%timeit cython_pisum_opt()\n", - "%timeit native_pisum()\n", - "%timeit native_pisum_opt()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "1 loops, best of 3: 493 ms per loop\n", - "1 loops, best of 3: 641 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10 loops, best of 3: 21.4 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10 loops, best of 3: 21.6 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10 loops, best of 3: 40.8 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10 loops, best of 3: 21.8 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1 loops, best of 3: 284 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10 loops, best of 3: 21.1 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10 loops, best of 3: 21.1 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10 loops, best of 3: 21.3 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 26 - }, + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 33\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mabs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhope_pisum_opt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1.644834071848065\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m1e-6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mabs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnumba_pisum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1.644834071848065\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m1e-6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 35\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0mabs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnative_pisum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1.644834071848065\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m1e-6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 36\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0mabs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnative_pisum_opt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1.644834071848065\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m<\u001b[0m \u001b[0;36m1e-6\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAssertionError\u001b[0m: " + ] + } + ], + "source": [ + "def pisum():\n", + " for j in range(1, 501):\n", + " sum = 0.0\n", + " f = 0.0\n", + " for k in range(1, 10001):\n", + " sum += 1.0/(k*k)\n", + " return sum\n", + "\n", + "def pisum_opt():\n", + " for j in range(1, 501):\n", + " sum = 0.0\n", + " f = 0.0\n", + " for k in range(1, 10001):\n", + " f += 1.\n", + " sum += 1.0/(f*f)\n", + " return sum\n", + "\n", + "hope_pisum = hope.jit(pisum)\n", + "hope_pisum_opt = hope.jit(pisum_opt)\n", + "\n", + "numba_pisum = numba.jit(pisum, nopython=True)\n", + "numba_pisum_opt = numba.jit(pisum_opt, nopython=True)\n", + "\n", + "native_pisum_mod = load(\"pisum\")\n", + "native_pisum = native_pisum_mod.run\n", + "\n", + "native_pisum_opt_mod = load(\"pisum_opt\")\n", + "native_pisum_opt = native_pisum_opt_mod.run\n", + "\n", + "\n", + "assert abs(pisum()-1.644834071848065) < 1e-6\n", + "assert abs(hope_pisum()-1.644834071848065) < 1e-6\n", + "assert abs(hope_pisum_opt()-1.644834071848065) < 1e-6\n", + "assert abs(numba_pisum()-1.644834071848065) < 1e-6\n", + "assert abs(native_pisum()-1.644834071848065) < 1e-6\n", + "assert abs(native_pisum_opt()-1.644834071848065) < 1e-6" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "%%cython\n", + "\n", + "cimport cython\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "@cython.locals(f=float)\n", + "@cython.cdivision(True)\n", + "def cython_pisum():\n", + " cdef double sum = 0.0\n", + " cdef int j, k\n", + " for j in range(1, 501):\n", + " sum = 0.0\n", + " for k in range(1, 10001):\n", + " sum += 1.0/(k*k)\n", + " return sum\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "@cython.locals(f=float)\n", + "@cython.cdivision(True)\n", + "def cython_pisum_opt():\n", + " cdef double sum = 0.0\n", + " cdef int j, k\n", + " for j in range(1, 501):\n", + " sum = 0.0\n", + " f = 0.0\n", + " for k in range(1, 10001):\n", + " f += 1.\n", + " sum += 1.0/(f*f)\n", + " return sum\n", + "\n", + "\n", + "assert abs(cython_pisum()-1.644834071848065) < 1e-6\n", + "assert abs(cython_pisum_opt()-1.644834071848065) < 1e-6" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "perf_comp_data([\"pisum\", \"pisum_opt\", \n", - " \"hope_pisum\", \"hope_pisum_opt\", \n", - " \"numba_pisum\", \"numba_pisum_opt\", \n", - " #\"cython_pisum\", \n", - " \"cython_pisum_opt\",\n", - " \"native_pisum\", \"native_pisum_opt\",], \n", - " None, rep=100)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: cython_pisum_opt , av. time sec: 0.02122343, min. time sec: 0.02094698, relative: 1.0\n", - "function: native_pisum_opt , av. time sec: 0.02158451, min. time sec: 0.02108502, relative: 1.0\n", - "function: native_pisum , av. time sec: 0.02167845, min. time sec: 0.02090883, relative: 1.0\n", - "function: numba_pisum_opt , av. time sec: 0.02173293, min. time sec: 0.02095199, relative: 1.0\n", - "function: hope_pisum_opt , av. time sec: 0.02241504, min. time sec: 0.02135611, relative: 1.1\n", - "function: hope_pisum , av. time sec: 0.02270293, min. time sec: 0.02136111, relative: 1.1\n", - "function: numba_pisum , av. time sec: 0.04188490, min. time sec: 0.04017806, relative: 2.0\n", - "function: pisum , av. time sec: 0.49351048, min. time sec: 0.48015594, relative: 23.3\n", - "function: pisum_opt , av. time sec: 0.64186037, min. time sec: 0.61331892, relative: 30.2\n" - ] - } - ], - "prompt_number": 27 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "740 ms ± 38.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "615 ms ± 8.21 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "39 ms ± 660 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "20.9 ms ± 401 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "21 ms ± 381 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "20.9 ms ± 547 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "20.8 ms ± 360 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "20.8 ms ± 484 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "32.8 ms ± 1.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "23.3 ms ± 1.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n" + ] + } + ], + "source": [ + "%timeit pisum()\n", + "%timeit pisum_opt()\n", + "%timeit hope_pisum()\n", + "%timeit hope_pisum_opt()\n", + "%timeit numba_pisum()\n", + "%timeit numba_pisum_opt()\n", + "%timeit cython_pisum()\n", + "%timeit cython_pisum_opt()\n", + "%timeit native_pisum()\n", + "%timeit native_pisum_opt()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 17 + "name": "stdout", + "output_type": "stream", + "text": [ + "function: cython_pisum_opt , av. time sec: 0.02031763, min. time sec: 0.02003632, relative: 1.0\n", + "function: cython_pisum , av. time sec: 0.02036748, min. time sec: 0.02007828, relative: 1.0\n", + "function: hope_pisum_opt , av. time sec: 0.02039336, min. time sec: 0.02009269, relative: 1.0\n", + "function: numba_pisum , av. time sec: 0.02047833, min. time sec: 0.02018560, relative: 1.0\n", + "function: numba_pisum_opt , av. time sec: 0.02050058, min. time sec: 0.02010900, relative: 1.0\n", + "function: native_pisum_opt , av. time sec: 0.02051785, min. time sec: 0.02011683, relative: 1.0\n", + "function: native_pisum , av. time sec: 0.02956523, min. time sec: 0.02909494, relative: 1.5\n", + "function: hope_pisum , av. time sec: 0.03828400, min. time sec: 0.03774484, relative: 1.9\n", + "function: pisum_opt , av. time sec: 0.62492522, min. time sec: 0.60418793, relative: 30.8\n", + "function: pisum , av. time sec: 0.78460755, min. time sec: 0.68841730, relative: 38.6\n" + ] } ], - "metadata": {} + "source": [ + "perf_comp_data([\"pisum\", \"pisum_opt\", \n", + " \"hope_pisum\", \"hope_pisum_opt\", \n", + " \"numba_pisum\", \"numba_pisum_opt\", \n", + " \"cython_pisum\", \n", + " \"cython_pisum_opt\",\n", + " \"native_pisum\", \"native_pisum_opt\",], \n", + " None, rep=100)" + ] } - ] -} \ No newline at end of file + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/native_cpp_gen.ipynb b/benchmarks/native_cpp_gen.ipynb index 20878e4..a66e17e 100644 --- a/benchmarks/native_cpp_gen.ipynb +++ b/benchmarks/native_cpp_gen.ipynb @@ -1,2267 +1,2434 @@ { - "metadata": { - "name": "" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IPython magic extension version_information" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the '%version_information' IPython magic extension in a notebook to display information about which versions of dependency package that was used to run the notebook.\n", + "Installation.\n", + "\n", + "Run\n", + "\n", + " pip install git+https://github.com/jrjohansson/version_information\n", + " \n", + " \n", + "to install this extension" + ] + }, { - "cells": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%load_ext version_information" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 1, + "data": { + "application/json": { + "Software versions": [ + { + "module": "Python", + "version": "3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]" + }, + { + "module": "IPython", + "version": "6.1.0" + }, + { + "module": "OS", + "version": "Darwin 15.6.0 x86_64 i386 64bit" + } + ] + }, + "text/html": [ + "
SoftwareVersion
Python3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
IPython6.1.0
OSDarwin 15.6.0 x86_64 i386 64bit
Mon Sep 04 16:11:03 2017 CEST
" + ], + "text/latex": [ + "\\begin{tabular}{|l|l|}\\hline\n", + "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", + "Python & 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] \\\\ \\hline\n", + "IPython & 6.1.0 \\\\ \\hline\n", + "OS & Darwin 15.6.0 x86\\_64 i386 64bit \\\\ \\hline\n", + "\\hline \\multicolumn{2}{|l|}{Mon Sep 04 16:11:03 2017 CEST} \\\\ \\hline\n", + "\\end{tabular}\n" + ], + "text/plain": [ + "Software versions\n", + "Python 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n", + "IPython 6.1.0\n", + "OS Darwin 15.6.0 x86_64 i386 64bit\n", + "Mon Sep 04 16:11:03 2017 CEST" + ] + }, + "execution_count": 2, "metadata": {}, - "source": [ - "IPython magic extension version_information\n" - ] - }, + "output_type": "execute_result" + } + ], + "source": [ + "%version_information" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Native CPP codes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fibonacci CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "!mkdir -p src" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use the '%version_information' IPython magic extension in a notebook to display information about which versions of dependency package that was used to run the notebook.\n", - "Installation" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/fib.cpp\n" ] - }, + } + ], + "source": [ + "%%file src/fib.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL fkt_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "\n", + "\n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline npy_int64 fib_J(\n", + " npy_int64 cn\n", + ");\n", + "inline npy_int64 fib_J(\n", + " npy_int64 cn\n", + ") {\n", + " if (cn < 2) {\n", + " return cn;\n", + " }\n", + " return fib_J(cn - 1) + fib_J(cn - 2); \n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "\n", + "void sighandler(int sig);\n", + "\n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n", + "\n", + "\n", + "extern \"C\" {\n", + "\n", + " PyObject * create_signature;\n", + "\n", + " struct sigaction slot;\n", + "\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + "\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObject * pn; npy_int64 cn;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 1\n", + " and (pn = PyTuple_GET_ITEM(args, 0)) and PyLong_CheckExact(pn)\n", + " ) {\n", + " cn = PyLong_AS_LONG(pn);\n", + " try {\n", + " return Py_BuildValue(\"l\", fib_J(\n", + " cn\n", + " ));\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"gANdcQBdcQFjaG9wZS5fYXN0ClZhcmlhYmxlCnECKYFxA31xBChYBAAAAGRpbXNxBUsAWAUAAABk\\ndHlwZXEGY2J1aWx0aW5zCmludApxB1gEAAAAbmFtZXEIWAEAAABucQl1YmFhLg==\\n\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for fib\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef fibMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef fibmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"fib\",\n", + " NULL,\n", + " -1,\n", + " fibMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_fib(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&fibmodule);\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Quicksort CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Installation" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/qsort_kernel.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%install_ext http://raw.github.com/jrjohansson/version_information/master/version_information.py" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Installed version_information.py. To use it, type:\n", - " %load_ext version_information\n" - ] - } - ], - "prompt_number": 3 - }, + } + ], + "source": [ + "%%file src/qsort_kernel.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL qsort_kernel_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "inline std::tuple qsort_kernel_d1JJ(PyObject * pa,\n", + " npy_intp const * __restrict__ sa,\n", + " npy_double * __restrict__ ca,\n", + " npy_int64 clo,\n", + " npy_int64 chi);\n", + "\n", + "inline std::tuple qsort_kernel_d1JJ(PyObject * pa,\n", + " npy_intp const * __restrict__ sa,\n", + " npy_double * __restrict__ ca,\n", + " npy_int64 clo,\n", + " npy_int64 chi){\n", + " npy_int64 ci = clo;\n", + " npy_int64 cj = chi;\n", + " npy_double cpivot;\n", + "\n", + " while (ci < chi) {\n", + " cpivot = ca[(int)((clo + chi) / 2)];\n", + "\n", + " while (ci <= cj) {\n", + " while (ca[ci] < cpivot) {\n", + " ci += 1;\n", + " }\n", + "\n", + " while (ca[cj] > cpivot) {\n", + " cj -= 1;\n", + " }\n", + "\n", + " if (ci <= cj) {\n", + " auto ctmp = ca[ci];\n", + " ca[ci] = ca[cj];\n", + " ca[cj] = ctmp;\n", + " ci += 1;\n", + " cj -= 1;\n", + " }\n", + " }\n", + "\n", + " if (clo < cj) {\n", + " qsort_kernel_d1JJ(pa, sa, ca, clo, cj);\n", + " }\n", + "\n", + " clo = ci;\n", + " cj = chi;\n", + " }\n", + "\n", + " return std::make_tuple((PyObject *)pa, sa, ca);\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pa;\n", + " PyObject * plo; npy_int64 clo;\n", + " PyObject * phi; npy_int64 chi;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 3\n", + " and (pa = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pa)\n", + " and PyArray_TYPE((PyArrayObject *)pa) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pa) == 1\n", + " and (plo = PyTuple_GET_ITEM(args, 1)) and PyLong_CheckExact(plo)\n", + " and (phi = PyTuple_GET_ITEM(args, 2)) and PyLong_CheckExact(phi)\n", + " ) {\n", + " if (!(pa.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pa)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on a!\");\n", + " return NULL;\n", + " }\n", + " clo = PyLong_AS_LONG(plo);\n", + " chi = PyLong_AS_LONG(phi);\n", + " try {\n", + " PyObject * res = std::get<0>(qsort_kernel_d1JJ(\n", + " pa, PyArray_SHAPE((PyArrayObject *)pa), (npy_double *)PyArray_DATA((PyArrayObject *)pa)\n", + " , clo\n", + " , chi\n", + " ));\n", + "\n", + " Py_INCREF(res);\n", + " return res;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'a'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'lo'\\np16\\nsg10\\nc__builtin__\\nint\\np17\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp18\\nRp19\\n(dp20\\ng8\\nS'hi'\\np21\\nsg10\\ng17\\nsg12\\nI0\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for qsort_kernel\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + " PyMethodDef qsort_kernelMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "}\n", + "\n", + "static struct PyModuleDef qsort_kernel_module = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"qsort_kernel\",\n", + " NULL,\n", + " -1,\n", + " qsort_kernelMethods\n", + "};\n", + "\n", + "PyMODINIT_FUNC PyInit_qsort_kernel(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&qsort_kernel_module);\n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pi sum CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 1, - "metadata": {}, - "source": [ - "Native CPP codes" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/pisum.cpp\n" ] - }, + } + ], + "source": [ + "%%file src/pisum.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pisum_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline npy_double pisum_();\n", + "\n", + "inline npy_double pisum_() {\n", + " double csum = 0;\n", + " int ck = 1;\n", + " for (int cj = 1; cj < 501; ++cj) {\n", + " csum = 0.0;\n", + " for (ck = 1; ck < 10001; ++ck) {\n", + " csum += (1.0 / (double)(ck * ck));\n", + " }\n", + " }\n", + "\n", + " return npy_double(csum);\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " { try {\n", + " return Py_BuildValue(\"d\", pisum_());\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\na.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pisum\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + "PyMethodDef pisumMethods[] = {\n", + "{ \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + "{ \"run\", run, METH_VARARGS, \"module function\" },\n", + "{ NULL, NULL, 0, NULL }\n", + "};\n", + "\n", + "static struct PyModuleDef pisum_module = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pisum\",\n", + " NULL,\n", + " -1,\n", + " pisumMethods\n", + "};\n", + "\n", + "PyMODINIT_FUNC PyInit_pisum(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pisum_module);\n", + "}\n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Fibonacci CPP" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/pisum_opt.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/fib.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL fib_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "\n", - "inline npy_int64 fib_J(npy_int64 cn);\n", - "\n", - "inline npy_int64 fib_J(npy_int64 cn) {\n", - "\tif (cn < 2) {\n", - "\t\treturn cn;\n", - "\t}\n", - "\treturn fib_J(cn - 1) + fib_J(cn - 2);\n", - "}\n", - "\n", - "\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObject * pn; npy_int64 cn;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 1\n", - "\t\t\t\tand (pn = PyTuple_GET_ITEM(args, 0)) and PyInt_CheckExact(pn)\n", - "\t\t\t) {\n", - "\t\t\t\tcn = PyInt_AS_LONG(pn);\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\treturn Py_BuildValue(\"l\", fib_J(\n", - "\t\t\t\t\t\t cn\n", - "\t\t\t\t\t));\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'n'\\np9\\nsS'dtype'\\np10\\nc__builtin__\\nint\\np11\\nsS'dims'\\np12\\nI0\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for fib\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef fibMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initfib(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"fib\", fibMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n", - "\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/fib.cpp\n" - ] - } - ], - "prompt_number": 2 - }, + } + ], + "source": [ + "%%file src/pisum_opt.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pisum_opt_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline npy_double pisum_opt_();\n", + "\n", + "inline npy_double pisum_opt_() {\n", + " npy_double csum = npy_double();\n", + " npy_intp ck = 1;\n", + " npy_double cf = 0.0;\n", + "\n", + " for (npy_intp cj = 1; cj < 501; ++cj) {\n", + " csum = 0.0;\n", + " cf = 0.0;\n", + " for (ck = 1; ck < 10001; ++ck) {\n", + " cf += 1.0;\n", + " auto c__sp0 = (cf * cf);\n", + " csum += (1.0 / c__sp0);\n", + " }\n", + " }\n", + " return csum;\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " { try {\n", + " return Py_BuildValue(\"d\", pisum_opt_());\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\na.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pisum_opt\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef pisum_optMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + " static struct PyModuleDef pisum_opt_module = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pisum_opt\",\n", + " NULL,\n", + " -1,\n", + " pisum_optMethods\n", + " };\n", + "\n", + " PyMODINIT_FUNC PyInit_pisum_opt(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pisum_opt_module);\n", + " }\n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 10th order poly log approx CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Quicksort CPP" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/ln.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/qsort_kernel.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL qsort_kernel_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "inline std::tuple qsort_kernel_d1JJ(PyObject * pa, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_intp const * __restrict__ sa, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_double * __restrict__ ca, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 clo, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 chi);\n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n", - "inline std::tuple qsort_kernel_d1JJ(PyObject * pa, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_intp const * __restrict__ sa, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_double * __restrict__ ca, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 clo, \n", - "\t \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 chi){\n", - "\tnpy_int64 ci = clo;\n", - "\tnpy_int64 cj = chi;\n", - "\tnpy_double cpivot;\n", - "\n", - "\twhile (ci < chi) {\n", - "\t\tcpivot = ca[(int)((clo + chi) / 2)];\n", - "\t\t\n", - "\t\twhile (ci <= cj) {\n", - "\t\t\twhile (ca[ci] < cpivot) {\n", - "\t\t\t\tci += 1;\n", - "\t\t\t}\n", - "\t\t\t\n", - "\t\t\twhile (ca[cj] > cpivot) {\n", - "\t\t\t\tcj -= 1;\n", - "\t\t\t}\n", - "\t\t\t\n", - "\t\t\tif (ci <= cj) {\n", - "\t\t\t\tauto ctmp = ca[ci];\n", - "\t\t\t\tca[ci] = ca[cj];\n", - "\t\t\t\tca[cj] = ctmp;\n", - "\t\t\t\tci += 1;\n", - "\t\t\t\tcj -= 1;\n", - "\t\t\t}\n", - "\t\t}\n", - "\t\t\n", - "\t\tif (clo < cj) {\n", - "\t\t\tqsort_kernel_d1JJ(pa, sa, ca, clo, cj);\n", - "\t\t}\n", - "\t\t\n", - "\t\tclo = ci;\n", - "\t\tcj = chi;\n", - "\t}\n", - "\t\n", - "\treturn std::make_tuple((PyObject *)pa, sa, ca);\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pa;\n", - "\t\t\tPyObject * plo; npy_int64 clo;\n", - "\t\t\tPyObject * phi; npy_int64 chi;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 3\n", - "\t\t\t\tand (pa = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pa)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pa) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pa) == 1\n", - "\t\t\t\tand (plo = PyTuple_GET_ITEM(args, 1)) and PyInt_CheckExact(plo)\n", - "\t\t\t\tand (phi = PyTuple_GET_ITEM(args, 2)) and PyInt_CheckExact(phi)\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pa.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pa)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on a!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tclo = PyInt_AS_LONG(plo);\n", - "\t\t\t\tchi = PyInt_AS_LONG(phi);\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tPyObject * res = std::get<0>(qsort_kernel_d1JJ(\n", - "\t\t\t\t\t\t pa, PyArray_SHAPE((PyArrayObject *)pa), (npy_double *)PyArray_DATA((PyArrayObject *)pa)\n", - "\t\t\t\t\t\t, clo\n", - "\t\t\t\t\t\t, chi\n", - "\t\t\t\t\t));\n", - "\n", - "\t\t\t\t\tPy_INCREF(res);\n", - "\t\t\t\t\treturn res;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'a'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'lo'\\np16\\nsg10\\nc__builtin__\\nint\\np17\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp18\\nRp19\\n(dp20\\ng8\\nS'hi'\\np21\\nsg10\\ng17\\nsg12\\nI0\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for qsort_kernel\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef qsort_kernelMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initqsort_kernel(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"qsort_kernel\", qsort_kernelMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/qsort_kernel.cpp\n" - ] - } - ], - "prompt_number": 3 - }, + } + ], + "source": [ + "%%file src/ln.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void ln_hope_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", + "\n", + "inline void ln_hope_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", + "\n", + " for (npy_intp i0 = 0; i0 < sY[0] - 0; ++i0) {\n", + " cY[(int)(i0)] = (cX[i0] - 1) - (std::pow((cX[i0] - 1), 2) / 2) + (std::pow((cX[i0] - 1), 3) / 3) - (std::pow((cX[i0] - 1), 4) / 4) + (std::pow((cX[i0] - 1), 5) / 5) - (std::pow((cX[i0] - 1), 6) / 6) + (std::pow((cX[i0] - 1), 7) / 7) - (std::pow((cX[i0] - 1), 8) / 8) + (std::pow((cX[i0] - 1), 9) / 9);\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pY;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", + " and (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", + " and PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " ln_hope_d1d1(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef lnMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef lnmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"ln\",\n", + " NULL,\n", + " -1,\n", + " lnMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_ln(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&lnmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Pi sum CPP" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/ln_exp.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/pisum.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL pisum_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline npy_double pisum_();\n", - "\n", - "inline npy_double pisum_() {\n", - "\tnpy_double csum = npy_double();\n", - "\tnpy_intp ck = 1;\n", - "\tfor (npy_intp cj = 1; cj < 501; ++cj) {\n", - "\t\tcsum = 0.0;\n", - "\t\tauto cf = 0.0;\n", - "\t\tfor (ck = 1; ck < 10001; ++ck) {\n", - "\t\t\tauto c__sp0 = (ck * ck);\n", - "\t\t\tcsum += (1.0 / c__sp0);\n", - "\t\t}\n", - "\t}\n", - "\t\n", - "\treturn csum;\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\t\t\t\ttry {\n", - "\t\t\t\t\treturn Py_BuildValue(\"d\", pisum_());\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\na.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for pisum\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef pisumMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initpisum(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"pisum\", pisumMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/pisum.cpp\n" - ] - } - ], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/pisum_opt.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL pisum_opt_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline npy_double pisum_opt_();\n", - "\n", - "inline npy_double pisum_opt_() {\n", - "\tnpy_double csum = npy_double();\n", - "\tnpy_intp ck = 1;\n", - "\tnpy_double cf = 0.0;\n", - "\t\n", - "\tfor (npy_intp cj = 1; cj < 501; ++cj) {\n", - "\t\tcsum = 0.0;\n", - "\t\tcf = 0.0;\n", - "\t\tfor (ck = 1; ck < 10001; ++ck) {\n", - "\t\t\tcf += 1.0;\n", - "\t\t\tauto c__sp0 = (cf * cf);\n", - "\t\t\tcsum += (1.0 / c__sp0);\n", - "\t\t}\n", - "\t}\n", - "\treturn csum;\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\t\t\t\ttry {\n", - "\t\t\t\t\treturn Py_BuildValue(\"d\", pisum_opt_());\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\na.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for pisum_opt\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef pisum_optMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initpisum_opt(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"pisum_opt\", pisum_optMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/pisum_opt.cpp\n" - ] - } - ], - "prompt_number": 5 - }, + } + ], + "source": [ + "%%file src/ln_exp.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_exp_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void ln_hope_exp_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", + "\n", + "inline void ln_hope_exp_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", + "\n", + " for (npy_intp i0 = 0; i0 < sX[0] - 0; ++i0) {\n", + " auto cx = (cX[i0] - 1);\n", + " auto cx2 = (cx * cx);\n", + " auto cx4 = (cx2 * cx2);\n", + " auto cx6 = (cx4 * cx2);\n", + " auto cx8 = (cx4 * cx4);\n", + " cY[i0] = cx - (cx2 / 2) + (cx * cx2 / 3) - (cx4 / 4) + (cx * cx4 / 5) - (cx6 / 6) + (cx6 * cx / 7) - (cx8 / 8) + (cx8 * cx / 9);\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pY;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", + " and (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", + " and PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " ln_hope_exp_d1d1(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope_exp\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + " PyMethodDef ln_expMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef ln_expmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"ln_exp\",\n", + " NULL,\n", + " -1,\n", + " ln_expMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_ln_exp(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&ln_expmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 1, - "metadata": {}, - "source": [ - "10th order poly log approx CPP" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/ln_opt.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/ln.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline void ln_hope_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", - "\n", - "inline void ln_hope_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", - "\t\n", - "\tfor (npy_intp i0 = 0; i0 < sY[0] - 0; ++i0) {\n", - "\t\tcY[(int)(i0)] = (cX[i0] - 1) - (std::pow((cX[i0] - 1), 2) / 2) + (std::pow((cX[i0] - 1), 3) / 3) - (std::pow((cX[i0] - 1), 4) / 4) + (std::pow((cX[i0] - 1), 5) / 5) - (std::pow((cX[i0] - 1), 6) / 6) + (std::pow((cX[i0] - 1), 7) / 7) - (std::pow((cX[i0] - 1), 8) / 8) + (std::pow((cX[i0] - 1), 9) / 9);\n", - "\t}\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pX;\n", - "\t\t\tPyObj pY;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", - "\t\t\t\tand (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", - "\t\t\t\tand (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tln_hope_d1d1(\n", - "\t\t\t\t\t\t pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", - "\t\t\t\t\t\t, pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", - "\t\t\t\t\t);\n", - "\t\t\t\t\tPy_INCREF(Py_None);\n", - "\t\t\t\t\treturn Py_None;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef ln_hopeMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initln(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"ln\", ln_hopeMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/ln.cpp\n" - ] - } - ], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/ln_exp.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_exp_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline void ln_hope_exp_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", - "\n", - "inline void ln_hope_exp_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", - "\n", - "\tfor (npy_intp i0 = 0; i0 < sX[0] - 0; ++i0) {\n", - "\t\tauto cx = (cX[i0] - 1);\n", - "\t\tauto cx2 = (cx * cx);\n", - "\t\tauto cx4 = (cx2 * cx2);\n", - "\t\tauto cx6 = (cx4 * cx2);\n", - "\t\tauto cx8 = (cx4 * cx4);\n", - "\t\tcY[i0] = cx - (cx2 / 2) + (cx * cx2 / 3) - (cx4 / 4) + (cx * cx4 / 5) - (cx6 / 6) + (cx6 * cx / 7) - (cx8 / 8) + (cx8 * cx / 9);\n", - "\t}\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pX;\n", - "\t\t\tPyObj pY;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", - "\t\t\t\tand (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", - "\t\t\t\tand (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tln_hope_exp_d1d1(\n", - "\t\t\t\t\t\t pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", - "\t\t\t\t\t\t, pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", - "\t\t\t\t\t);\n", - "\t\t\t\t\tPy_INCREF(Py_None);\n", - "\t\t\t\t\treturn Py_None;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope_exp\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef ln_hope_expMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initln_exp(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"ln_exp\", ln_hope_expMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/ln_exp.cpp\n" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/ln_opt.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_opt_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline void ln_hope_opt_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", - "\n", - "inline void ln_hope_opt_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n", - "\tfor (npy_intp i0 = 0; i0 < sY[0] - 0; ++i0) {\n", - "\t\tauto c__sp0 = (cX[i0] * cX[i0]);\n", - "\t\tauto c__sp1 = (c__sp0 * c__sp0);\n", - "\t\tauto c__sp2 = (c__sp1 * c__sp1);\n", - "\t\tauto c__sp3 = (c__sp2 * cX[i0]);\n", - "\t\tauto c__sp4 = (c__sp0 * cX[i0]);\n", - "\t\tauto c__sp5 = (c__sp4 * c__sp4);\n", - "\t\tauto c__sp6 = (c__sp5 * cX[i0]);\n", - "\t\tauto c__sp7 = (c__sp1 * cX[i0]);\n", - "\t\tcY[(int)(i0)] = (-7129.0 / 2520.0) + (28 * c__sp4) + (-(18 * c__sp0)) + (-(9 * c__sp2 / 8)) + (-(14 * c__sp5)) + (-(63 * c__sp1 / 2)) + (126 * c__sp7 / 5) + (9 * cX[i0]) + (c__sp3 / 9) + (36 * c__sp6 / 7);\n", - "\t}\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pX;\n", - "\t\t\tPyObj pY;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", - "\t\t\t\tand (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", - "\t\t\t\tand (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tln_hope_opt_d1d1(\n", - "\t\t\t\t\t\t pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", - "\t\t\t\t\t\t, pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", - "\t\t\t\t\t);\n", - "\t\t\t\t\tPy_INCREF(Py_None);\n", - "\t\t\t\t\treturn Py_None;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope_opt\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef ln_hope_optMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initln_opt(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"ln_opt\", ln_hope_optMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/ln_opt.cpp\n" - ] - } - ], - "prompt_number": 10 - }, + } + ], + "source": [ + "%%file src/ln_opt.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_opt_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void ln_hope_opt_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", + "\n", + "inline void ln_hope_opt_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", + "\n", + " for (npy_intp i0 = 0; i0 < sY[0] - 0; ++i0) {\n", + " auto c__sp0 = (cX[i0] * cX[i0]);\n", + " auto c__sp1 = (c__sp0 * c__sp0);\n", + " auto c__sp2 = (c__sp1 * c__sp1);\n", + " auto c__sp3 = (c__sp2 * cX[i0]);\n", + " auto c__sp4 = (c__sp0 * cX[i0]);\n", + " auto c__sp5 = (c__sp4 * c__sp4);\n", + " auto c__sp6 = (c__sp5 * cX[i0]);\n", + " auto c__sp7 = (c__sp1 * cX[i0]);\n", + " cY[(int)(i0)] = (-7129.0 / 2520.0) + (28 * c__sp4) + (-(18 * c__sp0)) + (-(9 * c__sp2 / 8)) + (-(14 * c__sp5)) + (-(63 * c__sp1 / 2)) + (126 * c__sp7 / 5) + (9 * cX[i0]) + (c__sp3 / 9) + (36 * c__sp6 / 7);\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pY;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", + " and (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", + " and PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " ln_hope_opt_d1d1(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope_opt\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef ln_optMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef ln_optmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"ln\",\n", + " NULL,\n", + " -1,\n", + " ln_optMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_ln_opt(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&ln_optmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simplify CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Simplify CPP" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/poly.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/poly.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL poly_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", - "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg);\n", - "\n", - "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", - "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg){\n", - "\t\n", - "\tnpy_double arg_i;\n", - "\tdouble sin_arg_i;\n", - "\tfor (npy_intp i0 = 0; i0 < sres[0] - 0; ++i0) {\n", - "\t\targ_i = carg[i0];\n", - "\t\tcres[(int)(i0)] = std::pow(std::sin(arg_i), 2) + (std::pow(arg_i, 3) + std::pow(arg_i, 2) - arg_i - 1) / (std::pow(arg_i, 2) + 2 * arg_i + 1) + std::pow(std::cos(arg_i), 2);\n", - "\t}\n", - "}\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pres;\n", - "\t\t\tPyObj parg;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", - "\t\t\t\tand (pres = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pres)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pres) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pres) == 1\n", - "\t\t\t\tand (parg = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(parg)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)parg) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)parg) == 1\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pres.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pres)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on res!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(parg.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)parg)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on arg!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tpoly_d1d1(\n", - "\t\t\t\t\t\t pres, PyArray_SHAPE((PyArrayObject *)pres), (npy_double *)PyArray_DATA((PyArrayObject *)pres)\n", - "\t\t\t\t\t\t, parg, PyArray_SHAPE((PyArrayObject *)parg), (npy_double *)PyArray_DATA((PyArrayObject *)parg)\n", - "\t\t\t\t\t);\n", - "\t\t\t\t\tPy_INCREF(Py_None);\n", - "\t\t\t\t\treturn Py_None;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'res'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'arg'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for poly\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef polyMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initpoly(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"poly\", polyMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/poly.cpp\n" - ] - } - ], - "prompt_number": 15 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/poly_opt.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL poly_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", - "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg);\n", - "\n", - "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", - "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg){\n", - "\tfor (npy_intp i0 = 0; i0 < sres[0] - 0; ++i0) {\n", - "\t\tcres[(int)(i0)] = carg[i0];\n", - "\t}\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pres;\n", - "\t\t\tPyObj parg;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", - "\t\t\t\tand (pres = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pres)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pres) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pres) == 1\n", - "\t\t\t\tand (parg = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(parg)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)parg) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)parg) == 1\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pres.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pres)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on res!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(parg.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)parg)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on arg!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tpoly_d1d1(\n", - "\t\t\t\t\t\t pres, PyArray_SHAPE((PyArrayObject *)pres), (npy_double *)PyArray_DATA((PyArrayObject *)pres)\n", - "\t\t\t\t\t\t, parg, PyArray_SHAPE((PyArrayObject *)parg), (npy_double *)PyArray_DATA((PyArrayObject *)parg)\n", - "\t\t\t\t\t);\n", - "\t\t\t\t\tPy_INCREF(Py_None);\n", - "\t\t\t\t\treturn Py_None;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'res'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'arg'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for poly\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef polyMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initpoly(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"poly\", polyMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/poly_opt.cpp\n" - ] - } - ], - "prompt_number": 7 - }, + } + ], + "source": [ + "%%file src/poly.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL poly_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres,\n", + " PyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg);\n", + "\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres,\n", + " PyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg){\n", + "\n", + " npy_double arg_i;\n", + " double sin_arg_i;\n", + " for (npy_intp i0 = 0; i0 < sres[0] - 0; ++i0) {\n", + " arg_i = carg[i0];\n", + " cres[(int)(i0)] = std::pow(std::sin(arg_i), 2) + (std::pow(arg_i, 3) + std::pow(arg_i, 2) - arg_i - 1) / (std::pow(arg_i, 2) + 2 * arg_i + 1) + std::pow(std::cos(arg_i), 2);\n", + " }\n", + "}\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pres;\n", + " PyObj parg;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pres = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pres)\n", + " and PyArray_TYPE((PyArrayObject *)pres) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pres) == 1\n", + " and (parg = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(parg)\n", + " and PyArray_TYPE((PyArrayObject *)parg) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)parg) == 1\n", + " ) {\n", + " if (!(pres.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pres)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on res!\");\n", + " return NULL;\n", + " }\n", + " if (!(parg.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)parg)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on arg!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " poly_d1d1(\n", + " pres, PyArray_SHAPE((PyArrayObject *)pres), (npy_double *)PyArray_DATA((PyArrayObject *)pres)\n", + " , parg, PyArray_SHAPE((PyArrayObject *)parg), (npy_double *)PyArray_DATA((PyArrayObject *)parg)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'res'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'arg'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for poly\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef polyMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + " static struct PyModuleDef polymodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"poly\",\n", + " NULL,\n", + " -1,\n", + " polyMethods\n", + " };\n", + "\n", + " PyMODINIT_FUNC PyInit_poly(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&polymodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 2, - "metadata": {}, - "source": [ - "Pairwise distance" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/poly_opt.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/pairwise.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL pairwise_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline void pairwise_d2d2JJ(PyObject * pX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_intp const * __restrict__ sX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pD, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_intp const * __restrict__ sD, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_double * __restrict__ cD, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 const cM, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 const cN);\n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n", - "inline void pairwise_d2d2JJ(PyObject * pX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_intp const * __restrict__ sX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_double * __restrict__ cX, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tPyObject * pD, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_intp const * __restrict__ sD, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_double * __restrict__ cD, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 const cM, \n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\tnpy_int64 const cN){\n", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n", - "\tnpy_double cd = 0.0;\n", - "\tnpy_double ctmp = 0.0;\n", - "\t\n", - "\tnpy_intp cj;\n", - "\tnpy_intp ck;\n", - "\tnpy_intp x_i_idx;\n", - "\tnpy_intp x_j_idx;\n", - "\tnpy_intp d_i_idx;\n", - "\tnpy_intp const xp = sX[1];\n", - "\tnpy_intp const dp = sD[1];\n", - "\t\n", - "\tfor (npy_intp ci = 0; ci < cM; ++ci) {\n", - "\t\tx_i_idx = ci*xp;\n", - "\t\td_i_idx = ci*dp;\n", - "\t\tfor (cj = 0; cj < cM; ++cj) {\n", - "\t\t\tcd = 0.0;\n", - "\t\t\tx_j_idx = cj*xp;\n", - "\t\t\tfor (ck = 0; ck < cN; ++ck) {\n", - "\t\t\t\tctmp = (cX[(x_i_idx + ck)] - cX[(x_j_idx + ck)]);\n", - "\t\t\t\tcd += (ctmp * ctmp);\n", - "\t\t\t}\n", - "\t\t\tcD[(d_i_idx + cj)] = std::sqrt(cd);\n", - "\t\t}\n", - "\t}\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pX;\n", - "\t\t\tPyObj pD;\n", - "\t\t\tPyObject * pM; npy_int64 cM;\n", - "\t\t\tPyObject * pN; npy_int64 cN;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 4\n", - "\t\t\t\tand (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 2\n", - "\t\t\t\tand (pD = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pD)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pD) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pD) == 2\n", - "\t\t\t\tand (pM = PyTuple_GET_ITEM(args, 2)) and PyInt_CheckExact(pM)\n", - "\t\t\t\tand (pN = PyTuple_GET_ITEM(args, 3)) and PyInt_CheckExact(pN)\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(pD.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pD)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on D!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tcM = PyInt_AS_LONG(pM);\n", - "\t\t\t\tcN = PyInt_AS_LONG(pN);\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tpairwise_d2d2JJ(\n", - "\t\t\t\t\t\t pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", - "\t\t\t\t\t\t, pD, PyArray_SHAPE((PyArrayObject *)pD), (npy_double *)PyArray_DATA((PyArrayObject *)pD)\n", - "\t\t\t\t\t\t, cM\n", - "\t\t\t\t\t\t, cN\n", - "\t\t\t\t\t);\n", - "\t\t\t\t\tPy_INCREF(Py_None);\n", - "\t\t\t\t\treturn Py_None;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'D'\\np16\\nsg10\\ng11\\nsg12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp17\\nRp18\\n(dp19\\ng8\\nS'M'\\np20\\nsg10\\nc__builtin__\\nint\\np21\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp22\\nRp23\\n(dp24\\ng8\\nS'N'\\np25\\nsg10\\ng21\\nsg12\\nI0\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for pairwise\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef pairwiseMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initpairwise(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"pairwise\", pairwiseMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/pairwise.cpp\n" - ] - } - ], - "prompt_number": 12 - }, + } + ], + "source": [ + "%%file src/poly_opt.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL poly_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + "\ttypedef PyObject * ptr_t;\n", + "\ttypedef PyArrayObject * arrptr_t;\n", + "\tPyObj(): dec(false), ptr(NULL) {}\n", + "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", + "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", + "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + "\toperator bool() const { return ptr; }\n", + "\toperator ptr_t() const { return ptr; }\n", + "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", + "\tbool dec;\n", + "\tptr_t ptr;\n", + "};\n", + "\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", + "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg);\n", + "\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", + "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg){\n", + "\tfor (npy_intp i0 = 0; i0 < sres[0] - 0; ++i0) {\n", + "\t\tcres[(int)(i0)] = carg[i0];\n", + "\t}\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + "\tPyObject * create_signature;\n", + "\tstruct sigaction slot;\n", + "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + "\t\t\treturn NULL;\n", + "\t\t}\n", + "\t\tPy_INCREF(create_signature);\n", + "\t\tmemset(&slot, 0, sizeof(slot));\n", + "\t\tslot.sa_handler = &sighandler;\n", + "\t\tsigaction(SIGSEGV, &slot, NULL);\n", + "\t\tsigaction(SIGBUS, &slot, NULL);\n", + "\t\tPy_INCREF(Py_None);\n", + "\t\treturn Py_None;\n", + "\t}\n", + "\tPyObject * run(PyObject * self, PyObject * args) {\n", + "\t\t{\n", + "\t\t\tPyObj pres;\n", + "\t\t\tPyObj parg;\n", + "\t\t\tif (\n", + "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + "\t\t\t\tand (pres = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pres)\n", + "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pres) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pres) == 1\n", + "\t\t\t\tand (parg = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(parg)\n", + "\t\t\t\tand PyArray_TYPE((PyArrayObject *)parg) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)parg) == 1\n", + "\t\t\t) {\n", + "\t\t\t\tif (!(pres.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pres)))) {\n", + "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on res!\");\n", + "\t\t\t\t\treturn NULL;\n", + "\t\t\t\t}\n", + "\t\t\t\tif (!(parg.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)parg)))) {\n", + "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on arg!\");\n", + "\t\t\t\t\treturn NULL;\n", + "\t\t\t\t}\n", + "\t\t\t\ttry {\n", + "\t\t\t\t\tpoly_d1d1(\n", + "\t\t\t\t\t\t pres, PyArray_SHAPE((PyArrayObject *)pres), (npy_double *)PyArray_DATA((PyArrayObject *)pres)\n", + "\t\t\t\t\t\t, parg, PyArray_SHAPE((PyArrayObject *)parg), (npy_double *)PyArray_DATA((PyArrayObject *)parg)\n", + "\t\t\t\t\t);\n", + "\t\t\t\t\tPy_INCREF(Py_None);\n", + "\t\t\t\t\treturn Py_None;\n", + "\t\t\t\t} catch (...) {\n", + "\t\t\t\t\treturn NULL;\n", + "\t\t\t\t}\n", + "\t\t\t} else\n", + "\t\t\t\tPyErr_Clear();\n", + "\t\t}\n", + "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'res'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'arg'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + "\t\tif (!signatures) {\n", + "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for poly\");\n", + "\t\t\treturn NULL;\n", + "\t\t}\n", + "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", + "\t}\n", + "\tPyMethodDef polyMethods[] = {\n", + "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", + "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", + "\t\t{ NULL, NULL }\n", + "\t};\n", + "\tPyMODINIT_FUNC initpoly(void) {\n", + "\t\timport_array();\n", + "\t\tPyImport_ImportModule(\"numpy\");\n", + "\t\t(void)Py_InitModule(\"poly\", polyMethods);\n", + "\t}\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + "\tstd::ostringstream buffer;\n", + "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + "\tvoid * stack[64];\n", + "\tstd::size_t depth = backtrace(stack, 64);\n", + "\tif (!depth)\n", + "\t\tbuffer << \" \" << std::endl;\n", + "\telse {\n", + "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", + "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", + "\t\t\tstd::string symbol = symbols[i];\n", + "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + "\t\t\t\t\tint status;\n", + "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + "\t\t\t\t\tif (!status) {\n", + "\t\t\t\t\t\tbuffer << \" \" \n", + "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", + "\t\t\t\t\t\t\t<< demangled\n", + "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", + "\t\t\t\t\t\t\t<< std::endl;\n", + "\t\t\t\t\t\tfree(demangled);\n", + "\t\t\t\t\t} else\n", + "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", + "\t\t\t\t} else\n", + "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", + "\t\t\t}\n", + "\t\t\tfree(symbols);\n", + "\t\t}\n", + "\t\tstd::cerr << buffer.str();\n", + "\t\tstd::exit(EXIT_FAILURE);\n", + "\t}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pairwise distance" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Star point spread function CPP" + "name": "stdout", + "output_type": "stream", + "text": [ + "Writing src/pairwise.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file src/pdf.cpp\n", - "#define PY_ARRAY_UNIQUE_SYMBOL pdf_ARRAY_API\n", - "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "struct PyObj {\n", - "\ttypedef PyObject * ptr_t;\n", - "\ttypedef PyArrayObject * arrptr_t;\n", - "\tPyObj(): dec(false), ptr(NULL) {}\n", - "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", - "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", - "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", - "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", - "\toperator bool() const { return ptr; }\n", - "\toperator ptr_t() const { return ptr; }\n", - "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", - "\tbool dec;\n", - "\tptr_t ptr;\n", - "};\n", - "\n", - "inline std::tuple pdf_f2l1d1f2JDd(\n", - " \tPyObject * pdensity\n", - " , npy_intp const * __restrict__ sdensity\n", - " , npy_float * __restrict__ cdensity\n", - "\t, PyObject * pdims\n", - "\t, npy_intp const * __restrict__ sdims\n", - "\t, npy_int64 * __restrict__ cdims\n", - "\t, PyObject * pcenter\n", - "\t, npy_intp const * __restrict__ scenter\n", - "\t, npy_double * __restrict__ ccenter\n", - "\t, PyObject * pw2D\n", - "\t, npy_intp const * __restrict__ sw2D\n", - "\t, npy_float * __restrict__ cw2D\n", - "\t, npy_int64 cr50\n", - "\t, npy_double cb\n", - "\t, npy_double ca);\n", - "\n", - "inline std::tuple pdf_f2l1d1f2JDd(\n", - " \tPyObject * pdensity\n", - " , npy_intp const * __restrict__ sdensity\n", - " , npy_float * __restrict__ cdensity\n", - "\t, PyObject * pdims\n", - "\t, npy_intp const * __restrict__ sdims\n", - "\t, npy_int64 * __restrict__ cdims\n", - "\t, PyObject * pcenter\n", - "\t, npy_intp const * __restrict__ scenter\n", - "\t, npy_double * __restrict__ ccenter\n", - "\t, PyObject * pw2D\n", - "\t, npy_intp const * __restrict__ sw2D\n", - "\t, npy_float * __restrict__ cw2D\n", - "\t, npy_int64 const cr50\n", - "\t, npy_double const cb\n", - "\t, npy_double const ca) {\n", - "\t\n", - "\tnpy_double cdr;\n", - "\tnpy_double c__sum0;\n", - "\tconst npy_double x_center = ccenter[0];\n", - "\tconst npy_double y_center = ccenter[1];\n", - "\tconst npy_intp len_0_sw2D = sw2D[0];\n", - "\tconst npy_intp len_1_sw2D = sw2D[1];\n", - "\tnpy_intp dc[] = {len_0_sw2D, len_1_sw2D};\n", - "\tPyObject * pc = PyArray_EMPTY(2, dc, NPY_FLOAT64, 0);\n", - "\tnpy_intp * sc = PyArray_SHAPE((PyArrayObject *)pc);\n", - "\tnpy_double * cc = (npy_double *)PyArray_DATA((PyArrayObject *)pc);\n", - "\t\n", - "\tnpy_intp cy = 0;\n", - "\tnpy_intp i0 = 0;\n", - "\tnpy_intp i1 = 0;\n", - "\tnpy_intp i2 = 0;\n", - "\tnpy_intp i3 = 0;\n", - "\t\n", - "\tnpy_intp sw2D_i0_idx;\n", - "\tnpy_intp sw2D_i2_idx;\n", - "\tnpy_intp density_x_idx;\n", - "\t\n", - "\tauto c__sp0 = ca * ca;\n", - "\tauto c__sp1 = cr50 * cr50;\n", - "\tauto c__sp2 = 1.0 / (c__sp0 * c__sp1);\n", - "\tauto c__sp4 = 0.3183098861846737 * c__sp2 * (-1 + cb);\n", - "\n", - "\tfor (npy_intp cx = 0; cx < cdims[(int)(0)]; ++cx) {\n", - "\t\t\n", - "\t\tdensity_x_idx = cx*sdensity[1];\n", - "\t\tfor (cy = 0; cy < cdims[(int)(1)]; ++cy) {\n", - "\t\t\t\n", - "\t\t\tcdr = std::sqrt(std::pow(cx - x_center, 2) + std::pow(cy - y_center, 2));\n", - "\t\t\tauto c__sp3 = cdr * cdr;\n", - "\t\t\tauto c__sp5 = c__sp4 * std::pow((1 + c__sp2 * c__sp3), -cb);\n", - "\t\t\t\n", - "\t\t\tfor (i0 = 0; i0 < len_0_sw2D - 0; ++i0) {\n", - "\t\t\t\t\n", - "\t\t\t\tsw2D_i0_idx = (i0)*len_1_sw2D;\n", - "\t\t\t\tfor (i1 = 0; i1 < len_1_sw2D - 0; ++i1) {\n", - "\t\t\t\t\tcc[sw2D_i0_idx + i1] = c__sp5 * cw2D[sw2D_i0_idx + i1];\n", - "\t\t\t\t}\n", - "\t\t\t}\n", - "\t\t\t\n", - "\t\t\tc__sum0 = 0;\n", - "\t\t\tfor (i2 = 0; i2 < len_0_sw2D - 0; ++i2) {\n", - "\t\t\t\t\n", - "\t\t\t\tsw2D_i2_idx = (i2)*len_1_sw2D;\n", - "\t\t\t\tfor (i3 = 0; i3 < len_1_sw2D - 0; ++i3) {\n", - "\t\t\t\t\tc__sum0 += cc[sw2D_i2_idx + i3];\n", - "\t\t\t\t}\n", - "\t\t\t}\n", - "\t\t\t\n", - "\t\t\tcdensity[(density_x_idx + cy)] = c__sum0;\n", - "\t\t}\n", - "\t}\n", - "\treturn std::make_tuple((PyObject *)pdensity, sdensity, cdensity);\n", - "}\n", - "\n", - "void sighandler(int sig);\n", - "#include \n", - "extern \"C\" {\n", - "\tPyObject * create_signature;\n", - "\tstruct sigaction slot;\n", - "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", - "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\tPy_INCREF(create_signature);\n", - "\t\tmemset(&slot, 0, sizeof(slot));\n", - "\t\tslot.sa_handler = &sighandler;\n", - "\t\tsigaction(SIGSEGV, &slot, NULL);\n", - "\t\tsigaction(SIGBUS, &slot, NULL);\n", - "\t\tPy_INCREF(Py_None);\n", - "\t\treturn Py_None;\n", - "\t}\n", - "\tPyObject * run(PyObject * self, PyObject * args) {\n", - "\t\t{\n", - "\t\t\tPyObj pdensity;\n", - "\t\t\tPyObj pdims;\n", - "\t\t\tPyObj pcenter;\n", - "\t\t\tPyObj pw2D;\n", - "\t\t\tPyObject * pr50; npy_int64 cr50;\n", - "\t\t\tPyObject * pb; npy_double cb;\n", - "\t\t\tPyObject * pa; npy_double ca;\n", - "\t\t\tif (\n", - "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 7\n", - "\t\t\t\tand (pdensity = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pdensity)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pdensity) == NPY_FLOAT32 and PyArray_NDIM((PyArrayObject *)pdensity) == 2\n", - "\t\t\t\tand (pdims = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pdims)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pdims) == NPY_INT64 and PyArray_NDIM((PyArrayObject *)pdims) == 1\n", - "\t\t\t\tand (pcenter = PyTuple_GET_ITEM(args, 2)) and PyArray_CheckExact(pcenter)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pcenter) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pcenter) == 1\n", - "\t\t\t\tand (pw2D = PyTuple_GET_ITEM(args, 3)) and PyArray_CheckExact(pw2D)\n", - "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pw2D) == NPY_FLOAT32 and PyArray_NDIM((PyArrayObject *)pw2D) == 2\n", - "\t\t\t\tand (pr50 = PyTuple_GET_ITEM(args, 4)) and PyInt_CheckExact(pr50)\n", - "\t\t\t\tand (pb = PyTuple_GET_ITEM(args, 5)) and PyFloat_CheckExact(pb)\n", - "\t\t\t\tand (pa = PyTuple_GET_ITEM(args, 6)) and PyArray_IsScalar(pa, Double)\n", - "\t\t\t) {\n", - "\t\t\t\tif (!(pdensity.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pdensity)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on density!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(pdims.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pdims)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on dims!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(pcenter.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pcenter)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on center!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tif (!(pw2D.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pw2D)))) {\n", - "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on w2D!\");\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t\tcr50 = PyInt_AS_LONG(pr50);\n", - "\t\t\t\tcb = PyFloat_AS_DOUBLE(pb);\n", - "\t\t\t\tca = PyArrayScalar_VAL(pa, Double);\n", - "\t\t\t\ttry {\n", - "\t\t\t\t\tPyObject * res = std::get<0>(pdf_f2l1d1f2JDd(\n", - "\t\t\t\t\t\t pdensity, PyArray_SHAPE((PyArrayObject *)pdensity), (npy_float *)PyArray_DATA((PyArrayObject *)pdensity)\n", - "\t\t\t\t\t\t, pdims, PyArray_SHAPE((PyArrayObject *)pdims), (npy_int64 *)PyArray_DATA((PyArrayObject *)pdims)\n", - "\t\t\t\t\t\t, pcenter, PyArray_SHAPE((PyArrayObject *)pcenter), (npy_double *)PyArray_DATA((PyArrayObject *)pcenter)\n", - "\t\t\t\t\t\t, pw2D, PyArray_SHAPE((PyArrayObject *)pw2D), (npy_float *)PyArray_DATA((PyArrayObject *)pw2D)\n", - "\t\t\t\t\t\t, cr50\n", - "\t\t\t\t\t\t, cb\n", - "\t\t\t\t\t\t, ca\n", - "\t\t\t\t\t));\n", - "\n", - "\t\t\t\t\tPy_INCREF(res);\n", - "\t\t\t\t\treturn res;\n", - "\t\t\t\t} catch (...) {\n", - "\t\t\t\t\treturn NULL;\n", - "\t\t\t\t}\n", - "\t\t\t} else\n", - "\t\t\t\tPyErr_Clear();\n", - "\t\t}\n", - "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'density'\\np9\\nsS'dtype'\\np10\\nS'float32'\\np11\\nsS'dims'\\np12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\ng12\\nsg10\\nS'int64'\\np16\\nsg12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp17\\nRp18\\n(dp19\\ng8\\nS'center'\\np20\\nsg10\\nS'float64'\\np21\\nsg12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp22\\nRp23\\n(dp24\\ng8\\nS'w2D'\\np25\\nsg10\\ng11\\nsg12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp26\\nRp27\\n(dp28\\ng8\\nS'r50'\\np29\\nsg10\\nc__builtin__\\nint\\np30\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp31\\nRp32\\n(dp33\\ng8\\nS'b'\\np34\\nsg10\\nc__builtin__\\nfloat\\np35\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp36\\nRp37\\n(dp38\\ng8\\nS'a'\\np39\\nsg10\\ng21\\nsg12\\nI0\\nsbaa.\", args);\n", - "\t\tif (!signatures) {\n", - "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for pdf\");\n", - "\t\t\treturn NULL;\n", - "\t\t}\n", - "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", - "\t}\n", - "\tPyMethodDef pdfMethods[] = {\n", - "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", - "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", - "\t\t{ NULL, NULL }\n", - "\t};\n", - "\tPyMODINIT_FUNC initpdf(void) {\n", - "\t\timport_array();\n", - "\t\tPyImport_ImportModule(\"numpy\");\n", - "\t\t(void)Py_InitModule(\"pdf\", pdfMethods);\n", - "\t}\n", - "}\n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "#include \n", - "void sighandler(int sig) {\n", - "\tstd::ostringstream buffer;\n", - "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", - "\tvoid * stack[64];\n", - "\tstd::size_t depth = backtrace(stack, 64);\n", - "\tif (!depth)\n", - "\t\tbuffer << \" \" << std::endl;\n", - "\telse {\n", - "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", - "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", - "\t\t\tstd::string symbol = symbols[i];\n", - "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", - "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", - "\t\t\t\t\tint status;\n", - "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", - "\t\t\t\t\tif (!status) {\n", - "\t\t\t\t\t\tbuffer << \" \" \n", - "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", - "\t\t\t\t\t\t\t<< demangled\n", - "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", - "\t\t\t\t\t\t\t<< std::endl;\n", - "\t\t\t\t\t\tfree(demangled);\n", - "\t\t\t\t\t} else\n", - "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t\t} else\n", - "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", - "\t\t\t}\n", - "\t\t\tfree(symbols);\n", - "\t\t}\n", - "\t\tstd::cerr << buffer.str();\n", - "\t\tstd::exit(EXIT_FAILURE);\n", - "\t}\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting src/pdf.cpp\n" - ] - } - ], - "prompt_number": 14 - }, + } + ], + "source": [ + "%%file src/pairwise.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pairwise_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void pairwise_d2d2JJ(PyObject * pX,\n", + " npy_intp const * __restrict__ sX,\n", + " npy_double * __restrict__ cX,\n", + " PyObject * pD,\n", + " npy_intp const * __restrict__ sD,\n", + " npy_double * __restrict__ cD,\n", + " npy_int64 const cM,\n", + " npy_int64 const cN);\n", + "\n", + "inline void pairwise_d2d2JJ(PyObject * pX,\n", + " npy_intp const * __restrict__ sX,\n", + " npy_double * __restrict__ cX,\n", + " PyObject * pD,\n", + " npy_intp const * __restrict__ sD,\n", + " npy_double * __restrict__ cD,\n", + " npy_int64 const cM,\n", + " npy_int64 const cN){\n", + "\n", + " npy_double cd = 0.0;\n", + " npy_double ctmp = 0.0;\n", + "\n", + " npy_intp cj;\n", + " npy_intp ck;\n", + " npy_intp x_i_idx;\n", + " npy_intp x_j_idx;\n", + " npy_intp d_i_idx;\n", + " npy_intp const xp = sX[1];\n", + " npy_intp const dp = sD[1];\n", + "\n", + " for (npy_intp ci = 0; ci < cM; ++ci) {\n", + " x_i_idx = ci*xp;\n", + " d_i_idx = ci*dp;\n", + " for (cj = 0; cj < cM; ++cj) {\n", + " cd = 0.0;\n", + " x_j_idx = cj*xp;\n", + " for (ck = 0; ck < cN; ++ck) {\n", + " ctmp = (cX[(x_i_idx + ck)] - cX[(x_j_idx + ck)]);\n", + " cd += (ctmp * ctmp);\n", + " }\n", + " cD[(d_i_idx + cj)] = std::sqrt(cd);\n", + " }\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pD;\n", + " PyObject * pM; npy_int64 cM;\n", + " PyObject * pN; npy_int64 cN;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 4\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 2\n", + " and (pD = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pD)\n", + " and PyArray_TYPE((PyArrayObject *)pD) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pD) == 2\n", + " and (pM = PyTuple_GET_ITEM(args, 2)) and PyLong_CheckExact(pM)\n", + " and (pN = PyTuple_GET_ITEM(args, 3)) and PyLong_CheckExact(pN)\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pD.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pD)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on D!\");\n", + " return NULL;\n", + " }\n", + " cM = PyLong_AS_LONG(pM);\n", + " cN = PyLong_AS_LONG(pN);\n", + " try {\n", + " pairwise_d2d2JJ(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pD, PyArray_SHAPE((PyArrayObject *)pD), (npy_double *)PyArray_DATA((PyArrayObject *)pD)\n", + " , cM\n", + " , cN\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'D'\\np16\\nsg10\\ng11\\nsg12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp17\\nRp18\\n(dp19\\ng8\\nS'M'\\np20\\nsg10\\nc__builtin__\\nint\\np21\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp22\\nRp23\\n(dp24\\ng8\\nS'N'\\np25\\nsg10\\ng21\\nsg12\\nI0\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pairwise\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef pairwiseMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef pairwisemodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pairwise\",\n", + " NULL,\n", + " -1,\n", + " pairwiseMethods\n", + " };\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_pairwise(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pairwisemodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Star point spread function CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ { - "cell_type": "heading", - "level": 1, - "metadata": {}, - "source": [ - "Python helper module" + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/pdf.cpp\n" ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file native_util.py\n", - "import os\n", - "import sys\n", - "\n", - "from numpy.distutils.misc_util import get_numpy_include_dirs\n", - "import setuptools\n", - "from os import listdir\n", - "# import tempfile\n", - "from hope import config\n", - "\n", - "def load(name):\n", - " compile(name, \"./src\")\n", - " module = __import__(name, globals(), locals(), [], -1)\n", - " return module\n", - "\n", - "\n", - "\n", - "def compile(name, src_folder, target_folder = \"./\"):\n", - " localfilename =os.path.join(src_folder, name)\n", - " \n", - " outfile, stdout, stderr, argv = None, None, None, sys.argv\n", - " try:\n", - " sys.stdout.flush(), sys.stderr.flush()\n", - " outpath = os.path.join(target_folder, \"{0}.out\".format(localfilename))\n", - " if os.path.exists(outpath):\n", - " os.remove(outpath)\n", - " \n", - " so_path = os.path.join(target_folder, \"{0}.so\".format(name))\n", - " if os.path.exists(so_path):\n", - " os.remove(so_path)\n", - " \n", - " outfile = open(outpath, 'w')\n", - " \n", - " if isinstance(sys.stdout, file) and isinstance(sys.stdout, file):\n", - " stdout, stderr = os.dup(sys.stdout.fileno()), os.dup(sys.stderr.fileno())\n", - " os.dup2(outfile.fileno(), sys.stdout.fileno())\n", - " os.dup2(outfile.fileno(), sys.stderr.fileno())\n", - " else:\n", - " stdout, stderr = sys.stdout, sys.stderr\n", - " sys.stdout, sys.stderr = outfile, outfile\n", - " try:\n", - " sources = \"./{0}.cpp\".format(localfilename)\n", - " sys.argv = [\"\", \"build_ext\",\n", - " \"-b\", target_folder, #--build-lib (-b) directory for compiled extension modules\n", - " \"-t\", \".\" #--build-temp - a rel path will result in a dir structure of -b at the cur position \n", - " ]\n", - " \n", - " from types import StringType\n", - " localfilename = StringType(localfilename)\n", - " sources = StringType(sources)\n", - " \n", - " setuptools.setup( \\\n", - " name = name\\\n", - " , ext_modules = [setuptools.Extension( \\\n", - " StringType(name) \\\n", - " , sources = [sources] \\\n", - " , extra_compile_args = config.cxxflags \\\n", - " )] \\\n", - " , include_dirs = get_numpy_include_dirs() \\\n", - " )\n", - " except SystemExit as e:\n", - " print(sys.stderr.write(str(e)))\n", - " sys.stdout.flush(), sys.stderr.flush()\n", - " finally:\n", - " if isinstance(stdout, int):\n", - " os.dup2(stdout, sys.stdout.fileno()), os.close(stdout)\n", - " elif not stdout is None:\n", - " sys.stdout = stdout\n", - " if isinstance(stderr, int):\n", - " os.dup2(stderr, sys.stderr.fileno()), os.close(stderr)\n", - " elif not stderr is None:\n", - " sys.stderr = stderr\n", - " if isinstance(outfile, file):\n", - " outfile.close()\n", - " sys.argv = argv\n", - " \n", - " with open(outpath) as outfile:\n", - " out = outfile.read()\n", - " \n", - " if not os.path.isfile(os.path.join(target_folder, \"{0}.so\".format(name))) or out.find(\"error:\") > -1:\n", - " print(out)\n", - " raise Exception(\"Error compiling function {0} (compiled to {1})\".format(localfilename, target_folder))\n", - " \n", - " if out.find(\"warning:\") > -1:\n", - " import warnings\n", - " warnings.warn(\"A warning has been issued during compilation:\\n%s\"%out)\n", - " \n", - " print(out)\n", - "\n", - "\n", - "def compile_all():\n", - " src_folder = \"./src\"\n", - " func_names = (src_file.split(\".cpp\")[0] for src_file in listdir(src_folder) if src_file.endswith(\".cpp\"))\n", - " for func_name in func_names:\n", - " compile(func_name, src_folder)\n", - " \n", - " \n", - "if __name__ == '__main__':\n", - " compile_all()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting native_util.py\n" - ] - } - ], - "prompt_number": 16 - }, + } + ], + "source": [ + "%%file src/pdf.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pdf_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline std::tuple pdf_f2l1d1f2JDd(\n", + " PyObject * pdensity\n", + " , npy_intp const * __restrict__ sdensity\n", + " , npy_float * __restrict__ cdensity\n", + " , PyObject * pdims\n", + " , npy_intp const * __restrict__ sdims\n", + " , npy_int64 * __restrict__ cdims\n", + " , PyObject * pcenter\n", + " , npy_intp const * __restrict__ scenter\n", + " , npy_double * __restrict__ ccenter\n", + " , PyObject * pw2D\n", + " , npy_intp const * __restrict__ sw2D\n", + " , npy_float * __restrict__ cw2D\n", + " , npy_int64 cr50\n", + " , npy_double cb\n", + " , npy_double ca);\n", + "\n", + "inline std::tuple pdf_f2l1d1f2JDd(\n", + " PyObject * pdensity\n", + " , npy_intp const * __restrict__ sdensity\n", + " , npy_float * __restrict__ cdensity\n", + " , PyObject * pdims\n", + " , npy_intp const * __restrict__ sdims\n", + " , npy_int64 * __restrict__ cdims\n", + " , PyObject * pcenter\n", + " , npy_intp const * __restrict__ scenter\n", + " , npy_double * __restrict__ ccenter\n", + " , PyObject * pw2D\n", + " , npy_intp const * __restrict__ sw2D\n", + " , npy_float * __restrict__ cw2D\n", + " , npy_int64 const cr50\n", + " , npy_double const cb\n", + " , npy_double const ca) {\n", + "\n", + " npy_double cdr;\n", + " npy_double c__sum0;\n", + " const npy_double x_center = ccenter[0];\n", + " const npy_double y_center = ccenter[1];\n", + " const npy_intp len_0_sw2D = sw2D[0];\n", + " const npy_intp len_1_sw2D = sw2D[1];\n", + " npy_intp dc[] = {len_0_sw2D, len_1_sw2D};\n", + " PyObject * pc = PyArray_EMPTY(2, dc, NPY_FLOAT64, 0);\n", + " npy_intp * sc = PyArray_SHAPE((PyArrayObject *)pc);\n", + " npy_double * cc = (npy_double *)PyArray_DATA((PyArrayObject *)pc);\n", + "\n", + " npy_intp cy = 0;\n", + " npy_intp i0 = 0;\n", + " npy_intp i1 = 0;\n", + " npy_intp i2 = 0;\n", + " npy_intp i3 = 0;\n", + "\n", + " npy_intp sw2D_i0_idx;\n", + " npy_intp sw2D_i2_idx;\n", + " npy_intp density_x_idx;\n", + "\n", + " auto c__sp0 = ca * ca;\n", + " auto c__sp1 = cr50 * cr50;\n", + " auto c__sp2 = 1.0 / (c__sp0 * c__sp1);\n", + " auto c__sp4 = 0.3183098861846737 * c__sp2 * (-1 + cb);\n", + "\n", + " for (npy_intp cx = 0; cx < cdims[(int)(0)]; ++cx) {\n", + "\n", + " density_x_idx = cx*sdensity[1];\n", + " for (cy = 0; cy < cdims[(int)(1)]; ++cy) {\n", + "\n", + " cdr = std::sqrt(std::pow(cx - x_center, 2) + std::pow(cy - y_center, 2));\n", + " auto c__sp3 = cdr * cdr;\n", + " auto c__sp5 = c__sp4 * std::pow((1 + c__sp2 * c__sp3), -cb);\n", + "\n", + " for (i0 = 0; i0 < len_0_sw2D - 0; ++i0) {\n", + "\n", + " sw2D_i0_idx = (i0)*len_1_sw2D;\n", + " for (i1 = 0; i1 < len_1_sw2D - 0; ++i1) {\n", + " cc[sw2D_i0_idx + i1] = c__sp5 * cw2D[sw2D_i0_idx + i1];\n", + " }\n", + " }\n", + "\n", + " c__sum0 = 0;\n", + " for (i2 = 0; i2 < len_0_sw2D - 0; ++i2) {\n", + "\n", + " sw2D_i2_idx = (i2)*len_1_sw2D;\n", + " for (i3 = 0; i3 < len_1_sw2D - 0; ++i3) {\n", + " c__sum0 += cc[sw2D_i2_idx + i3];\n", + " }\n", + " }\n", + "\n", + " cdensity[(density_x_idx + cy)] = c__sum0;\n", + " }\n", + " }\n", + " return std::make_tuple((PyObject *)pdensity, sdensity, cdensity);\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pdensity;\n", + " PyObj pdims;\n", + " PyObj pcenter;\n", + " PyObj pw2D;\n", + " PyObject * pr50; npy_int64 cr50;\n", + " PyObject * pb; npy_double cb;\n", + " PyObject * pa; npy_double ca;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 7\n", + " and (pdensity = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pdensity)\n", + " and PyArray_TYPE((PyArrayObject *)pdensity) == NPY_FLOAT32 and PyArray_NDIM((PyArrayObject *)pdensity) == 2\n", + " and (pdims = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pdims)\n", + " and PyArray_TYPE((PyArrayObject *)pdims) == NPY_INT64 and PyArray_NDIM((PyArrayObject *)pdims) == 1\n", + " and (pcenter = PyTuple_GET_ITEM(args, 2)) and PyArray_CheckExact(pcenter)\n", + " and PyArray_TYPE((PyArrayObject *)pcenter) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pcenter) == 1\n", + " and (pw2D = PyTuple_GET_ITEM(args, 3)) and PyArray_CheckExact(pw2D)\n", + " and PyArray_TYPE((PyArrayObject *)pw2D) == NPY_FLOAT32 and PyArray_NDIM((PyArrayObject *)pw2D) == 2\n", + " and (pr50 = PyTuple_GET_ITEM(args, 4)) and PyLong_CheckExact(pr50)\n", + " and (pb = PyTuple_GET_ITEM(args, 5)) and PyFloat_CheckExact(pb)\n", + " and (pa = PyTuple_GET_ITEM(args, 6)) and PyArray_IsScalar(pa, Double)\n", + " ) {\n", + " if (!(pdensity.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pdensity)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on density!\");\n", + " return NULL;\n", + " }\n", + " if (!(pdims.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pdims)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on dims!\");\n", + " return NULL;\n", + " }\n", + " if (!(pcenter.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pcenter)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on center!\");\n", + " return NULL;\n", + " }\n", + " if (!(pw2D.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pw2D)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on w2D!\");\n", + " return NULL;\n", + " }\n", + " cr50 = PyLong_AS_LONG(pr50);\n", + " cb = PyFloat_AS_DOUBLE(pb);\n", + " ca = PyArrayScalar_VAL(pa, Double);\n", + " try {\n", + " PyObject * res = std::get<0>(pdf_f2l1d1f2JDd(\n", + " pdensity, PyArray_SHAPE((PyArrayObject *)pdensity), (npy_float *)PyArray_DATA((PyArrayObject *)pdensity)\n", + " , pdims, PyArray_SHAPE((PyArrayObject *)pdims), (npy_int64 *)PyArray_DATA((PyArrayObject *)pdims)\n", + " , pcenter, PyArray_SHAPE((PyArrayObject *)pcenter), (npy_double *)PyArray_DATA((PyArrayObject *)pcenter)\n", + " , pw2D, PyArray_SHAPE((PyArrayObject *)pw2D), (npy_float *)PyArray_DATA((PyArrayObject *)pw2D)\n", + " , cr50\n", + " , cb\n", + " , ca\n", + " ));\n", + "\n", + " Py_INCREF(res);\n", + " return res;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'density'\\np9\\nsS'dtype'\\np10\\nS'float32'\\np11\\nsS'dims'\\np12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\ng12\\nsg10\\nS'int64'\\np16\\nsg12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp17\\nRp18\\n(dp19\\ng8\\nS'center'\\np20\\nsg10\\nS'float64'\\np21\\nsg12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp22\\nRp23\\n(dp24\\ng8\\nS'w2D'\\np25\\nsg10\\ng11\\nsg12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp26\\nRp27\\n(dp28\\ng8\\nS'r50'\\np29\\nsg10\\nc__builtin__\\nint\\np30\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp31\\nRp32\\n(dp33\\ng8\\nS'b'\\np34\\nsg10\\nc__builtin__\\nfloat\\np35\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp36\\nRp37\\n(dp38\\ng8\\nS'a'\\np39\\nsg10\\ng21\\nsg12\\nI0\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pdf\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef pdfMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + " static struct PyModuleDef pdfmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pdf\",\n", + " NULL,\n", + " -1,\n", + " pdfMethods\n", + " };\n", + "\n", + " PyMODINIT_FUNC PyInit_pdf(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pdfmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python helper module" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%file util.py\n", - "# Copyright (C) 2014 ETH Zurich, Institute for Astronomy\n", - "\n", - "'''\n", - "Created on Aug 4, 2014\n", - "\n", - "author: jakeret\n", - "'''\n", - "from __future__ import print_function, division, absolute_import, unicode_literals\n", - "import math\n", - "\n", - "def perf_comp_data(func_list, data_list, rep=5, number=1, extra_setup=None):\n", - " ''' Function to compare the performance of different functions.\n", - " \n", - " Parameters\n", - " ==========\n", - " func_list : list\n", - " list with function names as strings\n", - " data_list : list\n", - " list with data set names as strings\n", - " rep : int\n", - " number of repetitions of the whole comparison\n", - " number : int\n", - " number of executions for every function\n", - " '''\n", - " from timeit import repeat\n", - " res_list = {}\n", - " for name in enumerate(func_list):\n", - " if data_list is None:\n", - " stmt = \"%s()\"%(name[1])\n", - " setup = \"from __main__ import %s\"%(name[1]) \n", - " else:\n", - " stmt = \"%s(%s)\"%(name[1], data_list[name[0]])\n", - " setup = \"from __main__ import %s, %s\"%(name[1], data_list[name[0]])\n", - " if extra_setup is not None:\n", - " stmt = extra_setup + \"; \" + stmt\n", - " \n", - " results = repeat(stmt=stmt, setup=setup, repeat=rep, number=number)\n", - " \n", - " res_list[name[1]] = (median(results), min(results))\n", - " \n", - "# res_sort = sorted(res_list.iteritems(), key=lambda (k, v): (v, k))\n", - " res_sort = sorted(iter(res_list.items()), key=lambda k_v: (k_v[1], k_v[0]))\n", - " for func, (av_time, min_time) in res_sort:\n", - " rel = av_time / res_sort[0][1][0]\n", - " print('function: {0!s:20}, av. time sec: {1:>12.8f}, min. time sec: {2:>12.8f}, relative: {3:>9.1f}'.format(func, av_time, min_time, rel))\n", - "\n", - "def median(x):\n", - " s_x = sorted(x)\n", - " return (s_x[int(math.floor((len(s_x)-1)/2))] + s_x[int(math.ceil((len(s_x)-1)/2))])/2" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Overwriting util.py\n" - ] - } - ], - "prompt_number": 1 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting native_util.py\n" + ] + } + ], + "source": [ + "%%file native_util.py\n", + "import importlib\n", + "import os\n", + "import glob\n", + "import sys\n", + "\n", + "from numpy.distutils.misc_util import get_numpy_include_dirs\n", + "import setuptools\n", + "from os import listdir\n", + "# import tempfile\n", + "from hope import config\n", + "\n", + "try:\n", + " # python 3\n", + " import io\n", + " file = io.IOBase\n", + "except ImportError:\n", + " pass\n", + "\n", + "\n", + "def load(name):\n", + " compile(name, \"./src\")\n", + " module = importlib.import_module(name)\n", + " # module = __import__(name, globals(), locals(), [], -1)\n", + " return module\n", + "\n", + "\n", + "\n", + "def compile(name, src_folder, target_folder = \"./\"):\n", + " localfilename =os.path.join(src_folder, name)\n", + " \n", + " outfile, stdout, stderr, argv = None, None, None, sys.argv\n", + " try:\n", + " sys.stdout.flush(), sys.stderr.flush()\n", + " outpath = os.path.join(target_folder, \"{0}.out\".format(localfilename))\n", + " if os.path.exists(outpath):\n", + " os.remove(outpath)\n", + " \n", + " so_path = os.path.join(target_folder, \"{0}.so\".format(name))\n", + " if os.path.exists(so_path):\n", + " os.remove(so_path)\n", + " \n", + " outfile = open(outpath, 'w')\n", + " \n", + " try:\n", + " sys.stdout.fileno()\n", + " sys.stderr.fileno()\n", + " have_fileno = True\n", + " except OSError:\n", + " have_fileno = False\n", + " \n", + " if have_fileno and isinstance(sys.stdout, file) and isinstance(sys.stdout, file):\n", + " stdout, stderr = os.dup(sys.stdout.fileno()), os.dup(sys.stderr.fileno())\n", + " os.dup2(outfile.fileno(), sys.stdout.fileno())\n", + " os.dup2(outfile.fileno(), sys.stderr.fileno())\n", + " else:\n", + " stdout, stderr = sys.stdout, sys.stderr\n", + " sys.stdout, sys.stderr = outfile, outfile\n", + " try:\n", + " sources = \"./{0}.cpp\".format(localfilename)\n", + " sys.argv = [\"\", \"build_ext\",\n", + " \"-b\", target_folder, #--build-lib (-b) directory for compiled extension modules\n", + " \"-t\", \".\" #--build-temp - a rel path will result in a dir structure of -b at the cur position \n", + " ]\n", + " \n", + " localfilename = str(localfilename)\n", + " sources = str(sources)\n", + " \n", + " setuptools.setup( \\\n", + " name = name\\\n", + " , ext_modules = [setuptools.Extension( \\\n", + " name \\\n", + " , sources = [sources] \\\n", + " , extra_compile_args = config.cxxflags \\\n", + " )] \\\n", + " , include_dirs = get_numpy_include_dirs() \\\n", + " )\n", + " except SystemExit as e:\n", + " print(sys.stderr.write(str(e)))\n", + " sys.stdout.flush(), sys.stderr.flush()\n", + " finally:\n", + " if isinstance(stdout, int):\n", + " os.dup2(stdout, sys.stdout.fileno()), os.close(stdout)\n", + " elif not stdout is None:\n", + " sys.stdout = stdout\n", + " if isinstance(stderr, int):\n", + " os.dup2(stderr, sys.stderr.fileno()), os.close(stderr)\n", + " elif not stderr is None:\n", + " sys.stderr = stderr\n", + " if isinstance(outfile, file):\n", + " outfile.close()\n", + " sys.argv = argv\n", + " \n", + " with open(outpath) as outfile:\n", + " out = outfile.read()\n", + " \n", + " modules = glob.glob(os.path.join(target_folder, \"{}*.so\".format(name)))\n", + " \n", + " if not modules or out.find(\"error:\") > -1:\n", + " print(out)\n", + " raise Exception(\"Error compiling function {0} (compiled to {1})\".format(localfilename, target_folder))\n", + " \n", + " if out.find(\"warning:\") > -1:\n", + " import warnings\n", + " warnings.warn(\"A warning has been issued during compilation:\\n%s\"%out)\n", + " \n", + " print(out)\n", + "\n", + "\n", + "def compile_all():\n", + " src_folder = \"./src\"\n", + " func_names = (src_file.split(\".cpp\")[0] for src_file in listdir(src_folder) if src_file.endswith(\".cpp\"))\n", + " for func_name in func_names:\n", + " compile(func_name, src_folder)\n", + " \n", + " \n", + "if __name__ == '__main__':\n", + " compile_all()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting util.py\n" + ] } ], - "metadata": {} + "source": [ + "%%file util.py\n", + "# Copyright (C) 2014 ETH Zurich, Institute for Astronomy\n", + "\n", + "'''\n", + "Created on Aug 4, 2014\n", + "\n", + "author: jakeret\n", + "'''\n", + "from __future__ import print_function, division, absolute_import, unicode_literals\n", + "import math\n", + "\n", + "def perf_comp_data(func_list, data_list, rep=5, number=1, extra_setup=None):\n", + " ''' Function to compare the performance of different functions.\n", + " \n", + " Parameters\n", + " ==========\n", + " func_list : list\n", + " list with function names as strings\n", + " data_list : list\n", + " list with data set names as strings\n", + " rep : int\n", + " number of repetitions of the whole comparison\n", + " number : int\n", + " number of executions for every function\n", + " '''\n", + " from timeit import repeat\n", + " res_list = {}\n", + " for name in enumerate(func_list):\n", + " if data_list is None:\n", + " stmt = \"%s()\"%(name[1])\n", + " setup = \"from __main__ import %s\"%(name[1]) \n", + " else:\n", + " stmt = \"%s(%s)\"%(name[1], data_list[name[0]])\n", + " setup = \"from __main__ import %s, %s\"%(name[1], data_list[name[0]])\n", + " if extra_setup is not None:\n", + " stmt = extra_setup + \"; \" + stmt\n", + " \n", + " results = repeat(stmt=stmt, setup=setup, repeat=rep, number=number)\n", + " \n", + " res_list[name[1]] = (median(results), min(results))\n", + " \n", + "# res_sort = sorted(res_list.iteritems(), key=lambda (k, v): (v, k))\n", + " res_sort = sorted(iter(res_list.items()), key=lambda k_v: (k_v[1], k_v[0]))\n", + " for func, (av_time, min_time) in res_sort:\n", + " rel = av_time / res_sort[0][1][0]\n", + " print('function: {0!s:20}, av. time sec: {1:>12.8f}, min. time sec: {2:>12.8f}, relative: {3:>9.1f}'.format(func, av_time, min_time, rel))\n", + "\n", + "def median(x):\n", + " s_x = sorted(x)\n", + " return (s_x[int(math.floor((len(s_x)-1)/2))] + s_x[int(math.ceil((len(s_x)-1)/2))])/2" + ] } - ] -} \ No newline at end of file + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/native_cpp_gen.nbconvert.ipynb b/benchmarks/native_cpp_gen.nbconvert.ipynb new file mode 100644 index 0000000..716e3c3 --- /dev/null +++ b/benchmarks/native_cpp_gen.nbconvert.ipynb @@ -0,0 +1,2434 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IPython magic extension version_information" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use the '%version_information' IPython magic extension in a notebook to display information about which versions of dependency package that was used to run the notebook.\n", + "Installation.\n", + "\n", + "Run\n", + "\n", + " pip install git+https://github.com/jrjohansson/version_information\n", + " \n", + " \n", + "to install this extension" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%load_ext version_information" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "application/json": { + "Software versions": [ + { + "module": "Python", + "version": "3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]" + }, + { + "module": "IPython", + "version": "6.1.0" + }, + { + "module": "OS", + "version": "Darwin 15.6.0 x86_64 i386 64bit" + } + ] + }, + "text/html": [ + "
SoftwareVersion
Python3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
IPython6.1.0
OSDarwin 15.6.0 x86_64 i386 64bit
Mon Sep 04 16:13:15 2017 CEST
" + ], + "text/latex": [ + "\\begin{tabular}{|l|l|}\\hline\n", + "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", + "Python & 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] \\\\ \\hline\n", + "IPython & 6.1.0 \\\\ \\hline\n", + "OS & Darwin 15.6.0 x86\\_64 i386 64bit \\\\ \\hline\n", + "\\hline \\multicolumn{2}{|l|}{Mon Sep 04 16:13:15 2017 CEST} \\\\ \\hline\n", + "\\end{tabular}\n" + ], + "text/plain": [ + "Software versions\n", + "Python 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n", + "IPython 6.1.0\n", + "OS Darwin 15.6.0 x86_64 i386 64bit\n", + "Mon Sep 04 16:13:15 2017 CEST" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%version_information" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Native CPP codes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fibonacci CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "!mkdir -p src" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/fib.cpp\n" + ] + } + ], + "source": [ + "%%file src/fib.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL fkt_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "\n", + "\n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline npy_int64 fib_J(\n", + " npy_int64 cn\n", + ");\n", + "inline npy_int64 fib_J(\n", + " npy_int64 cn\n", + ") {\n", + " if (cn < 2) {\n", + " return cn;\n", + " }\n", + " return fib_J(cn - 1) + fib_J(cn - 2); \n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "\n", + "void sighandler(int sig);\n", + "\n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n", + "\n", + "\n", + "extern \"C\" {\n", + "\n", + " PyObject * create_signature;\n", + "\n", + " struct sigaction slot;\n", + "\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + "\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObject * pn; npy_int64 cn;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 1\n", + " and (pn = PyTuple_GET_ITEM(args, 0)) and PyLong_CheckExact(pn)\n", + " ) {\n", + " cn = PyLong_AS_LONG(pn);\n", + " try {\n", + " return Py_BuildValue(\"l\", fib_J(\n", + " cn\n", + " ));\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"gANdcQBdcQFjaG9wZS5fYXN0ClZhcmlhYmxlCnECKYFxA31xBChYBAAAAGRpbXNxBUsAWAUAAABk\\ndHlwZXEGY2J1aWx0aW5zCmludApxB1gEAAAAbmFtZXEIWAEAAABucQl1YmFhLg==\\n\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for fib\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef fibMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef fibmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"fib\",\n", + " NULL,\n", + " -1,\n", + " fibMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_fib(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&fibmodule);\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Quicksort CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/qsort_kernel.cpp\n" + ] + } + ], + "source": [ + "%%file src/qsort_kernel.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL qsort_kernel_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "inline std::tuple qsort_kernel_d1JJ(PyObject * pa,\n", + " npy_intp const * __restrict__ sa,\n", + " npy_double * __restrict__ ca,\n", + " npy_int64 clo,\n", + " npy_int64 chi);\n", + "\n", + "inline std::tuple qsort_kernel_d1JJ(PyObject * pa,\n", + " npy_intp const * __restrict__ sa,\n", + " npy_double * __restrict__ ca,\n", + " npy_int64 clo,\n", + " npy_int64 chi){\n", + " npy_int64 ci = clo;\n", + " npy_int64 cj = chi;\n", + " npy_double cpivot;\n", + "\n", + " while (ci < chi) {\n", + " cpivot = ca[(int)((clo + chi) / 2)];\n", + "\n", + " while (ci <= cj) {\n", + " while (ca[ci] < cpivot) {\n", + " ci += 1;\n", + " }\n", + "\n", + " while (ca[cj] > cpivot) {\n", + " cj -= 1;\n", + " }\n", + "\n", + " if (ci <= cj) {\n", + " auto ctmp = ca[ci];\n", + " ca[ci] = ca[cj];\n", + " ca[cj] = ctmp;\n", + " ci += 1;\n", + " cj -= 1;\n", + " }\n", + " }\n", + "\n", + " if (clo < cj) {\n", + " qsort_kernel_d1JJ(pa, sa, ca, clo, cj);\n", + " }\n", + "\n", + " clo = ci;\n", + " cj = chi;\n", + " }\n", + "\n", + " return std::make_tuple((PyObject *)pa, sa, ca);\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pa;\n", + " PyObject * plo; npy_int64 clo;\n", + " PyObject * phi; npy_int64 chi;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 3\n", + " and (pa = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pa)\n", + " and PyArray_TYPE((PyArrayObject *)pa) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pa) == 1\n", + " and (plo = PyTuple_GET_ITEM(args, 1)) and PyLong_CheckExact(plo)\n", + " and (phi = PyTuple_GET_ITEM(args, 2)) and PyLong_CheckExact(phi)\n", + " ) {\n", + " if (!(pa.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pa)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on a!\");\n", + " return NULL;\n", + " }\n", + " clo = PyLong_AS_LONG(plo);\n", + " chi = PyLong_AS_LONG(phi);\n", + " try {\n", + " PyObject * res = std::get<0>(qsort_kernel_d1JJ(\n", + " pa, PyArray_SHAPE((PyArrayObject *)pa), (npy_double *)PyArray_DATA((PyArrayObject *)pa)\n", + " , clo\n", + " , chi\n", + " ));\n", + "\n", + " Py_INCREF(res);\n", + " return res;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'a'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'lo'\\np16\\nsg10\\nc__builtin__\\nint\\np17\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp18\\nRp19\\n(dp20\\ng8\\nS'hi'\\np21\\nsg10\\ng17\\nsg12\\nI0\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for qsort_kernel\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + " PyMethodDef qsort_kernelMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "}\n", + "\n", + "static struct PyModuleDef qsort_kernel_module = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"qsort_kernel\",\n", + " NULL,\n", + " -1,\n", + " qsort_kernelMethods\n", + "};\n", + "\n", + "PyMODINIT_FUNC PyInit_qsort_kernel(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&qsort_kernel_module);\n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pi sum CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/pisum.cpp\n" + ] + } + ], + "source": [ + "%%file src/pisum.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pisum_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline npy_double pisum_();\n", + "\n", + "inline npy_double pisum_() {\n", + " double csum = 0;\n", + " int ck = 1;\n", + " for (int cj = 1; cj < 501; ++cj) {\n", + " csum = 0.0;\n", + " for (ck = 1; ck < 10001; ++ck) {\n", + " csum += (1.0 / (double)(ck * ck));\n", + " }\n", + " }\n", + "\n", + " return npy_double(csum);\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " { try {\n", + " return Py_BuildValue(\"d\", pisum_());\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\na.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pisum\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + "PyMethodDef pisumMethods[] = {\n", + "{ \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + "{ \"run\", run, METH_VARARGS, \"module function\" },\n", + "{ NULL, NULL, 0, NULL }\n", + "};\n", + "\n", + "static struct PyModuleDef pisum_module = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pisum\",\n", + " NULL,\n", + " -1,\n", + " pisumMethods\n", + "};\n", + "\n", + "PyMODINIT_FUNC PyInit_pisum(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pisum_module);\n", + "}\n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/pisum_opt.cpp\n" + ] + } + ], + "source": [ + "%%file src/pisum_opt.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pisum_opt_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline npy_double pisum_opt_();\n", + "\n", + "inline npy_double pisum_opt_() {\n", + " npy_double csum = npy_double();\n", + " npy_intp ck = 1;\n", + " npy_double cf = 0.0;\n", + "\n", + " for (npy_intp cj = 1; cj < 501; ++cj) {\n", + " csum = 0.0;\n", + " cf = 0.0;\n", + " for (ck = 1; ck < 10001; ++ck) {\n", + " cf += 1.0;\n", + " auto c__sp0 = (cf * cf);\n", + " csum += (1.0 / c__sp0);\n", + " }\n", + " }\n", + " return csum;\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " { try {\n", + " return Py_BuildValue(\"d\", pisum_opt_());\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\na.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pisum_opt\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef pisum_optMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + " static struct PyModuleDef pisum_opt_module = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pisum_opt\",\n", + " NULL,\n", + " -1,\n", + " pisum_optMethods\n", + " };\n", + "\n", + " PyMODINIT_FUNC PyInit_pisum_opt(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pisum_opt_module);\n", + " }\n", + "}\n", + "\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 10th order poly log approx CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/ln.cpp\n" + ] + } + ], + "source": [ + "%%file src/ln.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void ln_hope_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", + "\n", + "inline void ln_hope_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", + "\n", + " for (npy_intp i0 = 0; i0 < sY[0] - 0; ++i0) {\n", + " cY[(int)(i0)] = (cX[i0] - 1) - (std::pow((cX[i0] - 1), 2) / 2) + (std::pow((cX[i0] - 1), 3) / 3) - (std::pow((cX[i0] - 1), 4) / 4) + (std::pow((cX[i0] - 1), 5) / 5) - (std::pow((cX[i0] - 1), 6) / 6) + (std::pow((cX[i0] - 1), 7) / 7) - (std::pow((cX[i0] - 1), 8) / 8) + (std::pow((cX[i0] - 1), 9) / 9);\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pY;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", + " and (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", + " and PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " ln_hope_d1d1(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef lnMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef lnmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"ln\",\n", + " NULL,\n", + " -1,\n", + " lnMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_ln(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&lnmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/ln_exp.cpp\n" + ] + } + ], + "source": [ + "%%file src/ln_exp.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_exp_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void ln_hope_exp_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", + "\n", + "inline void ln_hope_exp_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", + "\n", + " for (npy_intp i0 = 0; i0 < sX[0] - 0; ++i0) {\n", + " auto cx = (cX[i0] - 1);\n", + " auto cx2 = (cx * cx);\n", + " auto cx4 = (cx2 * cx2);\n", + " auto cx6 = (cx4 * cx2);\n", + " auto cx8 = (cx4 * cx4);\n", + " cY[i0] = cx - (cx2 / 2) + (cx * cx2 / 3) - (cx4 / 4) + (cx * cx4 / 5) - (cx6 / 6) + (cx6 * cx / 7) - (cx8 / 8) + (cx8 * cx / 9);\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pY;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", + " and (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", + " and PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " ln_hope_exp_d1d1(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope_exp\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + " PyMethodDef ln_expMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef ln_expmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"ln_exp\",\n", + " NULL,\n", + " -1,\n", + " ln_expMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_ln_exp(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&ln_expmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/ln_opt.cpp\n" + ] + } + ], + "source": [ + "%%file src/ln_opt.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL ln_hope_opt_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void ln_hope_opt_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY);\n", + "\n", + "inline void ln_hope_opt_d1d1(PyObject * pX, npy_intp const * __restrict__ sX, npy_double * __restrict__ cX,\n", + " PyObject * pY, npy_intp const * __restrict__ sY, npy_double * __restrict__ cY){\n", + "\n", + " for (npy_intp i0 = 0; i0 < sY[0] - 0; ++i0) {\n", + " auto c__sp0 = (cX[i0] * cX[i0]);\n", + " auto c__sp1 = (c__sp0 * c__sp0);\n", + " auto c__sp2 = (c__sp1 * c__sp1);\n", + " auto c__sp3 = (c__sp2 * cX[i0]);\n", + " auto c__sp4 = (c__sp0 * cX[i0]);\n", + " auto c__sp5 = (c__sp4 * c__sp4);\n", + " auto c__sp6 = (c__sp5 * cX[i0]);\n", + " auto c__sp7 = (c__sp1 * cX[i0]);\n", + " cY[(int)(i0)] = (-7129.0 / 2520.0) + (28 * c__sp4) + (-(18 * c__sp0)) + (-(9 * c__sp2 / 8)) + (-(14 * c__sp5)) + (-(63 * c__sp1 / 2)) + (126 * c__sp7 / 5) + (9 * cX[i0]) + (c__sp3 / 9) + (36 * c__sp6 / 7);\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pY;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 1\n", + " and (pY = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pY)\n", + " and PyArray_TYPE((PyArrayObject *)pY) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pY) == 1\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pY.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pY)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on Y!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " ln_hope_opt_d1d1(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pY, PyArray_SHAPE((PyArrayObject *)pY), (npy_double *)PyArray_DATA((PyArrayObject *)pY)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'Y'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for ln_hope_opt\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef ln_optMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef ln_optmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"ln\",\n", + " NULL,\n", + " -1,\n", + " ln_optMethods\n", + " };\n", + "\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_ln_opt(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&ln_optmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simplify CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/poly.cpp\n" + ] + } + ], + "source": [ + "%%file src/poly.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL poly_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres,\n", + " PyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg);\n", + "\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres,\n", + " PyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg){\n", + "\n", + " npy_double arg_i;\n", + " double sin_arg_i;\n", + " for (npy_intp i0 = 0; i0 < sres[0] - 0; ++i0) {\n", + " arg_i = carg[i0];\n", + " cres[(int)(i0)] = std::pow(std::sin(arg_i), 2) + (std::pow(arg_i, 3) + std::pow(arg_i, 2) - arg_i - 1) / (std::pow(arg_i, 2) + 2 * arg_i + 1) + std::pow(std::cos(arg_i), 2);\n", + " }\n", + "}\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pres;\n", + " PyObj parg;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + " and (pres = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pres)\n", + " and PyArray_TYPE((PyArrayObject *)pres) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pres) == 1\n", + " and (parg = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(parg)\n", + " and PyArray_TYPE((PyArrayObject *)parg) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)parg) == 1\n", + " ) {\n", + " if (!(pres.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pres)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on res!\");\n", + " return NULL;\n", + " }\n", + " if (!(parg.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)parg)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on arg!\");\n", + " return NULL;\n", + " }\n", + " try {\n", + " poly_d1d1(\n", + " pres, PyArray_SHAPE((PyArrayObject *)pres), (npy_double *)PyArray_DATA((PyArrayObject *)pres)\n", + " , parg, PyArray_SHAPE((PyArrayObject *)parg), (npy_double *)PyArray_DATA((PyArrayObject *)parg)\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'res'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'arg'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for poly\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef polyMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + " static struct PyModuleDef polymodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"poly\",\n", + " NULL,\n", + " -1,\n", + " polyMethods\n", + " };\n", + "\n", + " PyMODINIT_FUNC PyInit_poly(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&polymodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/poly_opt.cpp\n" + ] + } + ], + "source": [ + "%%file src/poly_opt.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL poly_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + "\ttypedef PyObject * ptr_t;\n", + "\ttypedef PyArrayObject * arrptr_t;\n", + "\tPyObj(): dec(false), ptr(NULL) {}\n", + "\tPyObj(ptr_t p): dec(false), ptr(p) {}\n", + "\t~PyObj() { if(dec) Py_DECREF(ptr); }\n", + "\tPyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + "\tPyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + "\toperator bool() const { return ptr; }\n", + "\toperator ptr_t() const { return ptr; }\n", + "\toperator arrptr_t() const { return (arrptr_t)ptr; }\n", + "\tbool dec;\n", + "\tptr_t ptr;\n", + "};\n", + "\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", + "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg);\n", + "\n", + "inline void poly_d1d1(PyObject * pres, npy_intp const * __restrict__ sres, npy_double * __restrict__ cres, \n", + "\t\t\t\t\t\t\t\t\t\t\tPyObject * parg, npy_intp const * __restrict__ sarg, npy_double * __restrict__ carg){\n", + "\tfor (npy_intp i0 = 0; i0 < sres[0] - 0; ++i0) {\n", + "\t\tcres[(int)(i0)] = carg[i0];\n", + "\t}\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + "\tPyObject * create_signature;\n", + "\tstruct sigaction slot;\n", + "\tPyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + "\t\tif (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + "\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + "\t\t\treturn NULL;\n", + "\t\t}\n", + "\t\tPy_INCREF(create_signature);\n", + "\t\tmemset(&slot, 0, sizeof(slot));\n", + "\t\tslot.sa_handler = &sighandler;\n", + "\t\tsigaction(SIGSEGV, &slot, NULL);\n", + "\t\tsigaction(SIGBUS, &slot, NULL);\n", + "\t\tPy_INCREF(Py_None);\n", + "\t\treturn Py_None;\n", + "\t}\n", + "\tPyObject * run(PyObject * self, PyObject * args) {\n", + "\t\t{\n", + "\t\t\tPyObj pres;\n", + "\t\t\tPyObj parg;\n", + "\t\t\tif (\n", + "\t\t\t\tPyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 2\n", + "\t\t\t\tand (pres = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pres)\n", + "\t\t\t\tand PyArray_TYPE((PyArrayObject *)pres) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pres) == 1\n", + "\t\t\t\tand (parg = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(parg)\n", + "\t\t\t\tand PyArray_TYPE((PyArrayObject *)parg) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)parg) == 1\n", + "\t\t\t) {\n", + "\t\t\t\tif (!(pres.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pres)))) {\n", + "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on res!\");\n", + "\t\t\t\t\treturn NULL;\n", + "\t\t\t\t}\n", + "\t\t\t\tif (!(parg.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)parg)))) {\n", + "\t\t\t\t\tPyErr_SetString(PyExc_ValueError, \"Invalid Argument type on arg!\");\n", + "\t\t\t\t\treturn NULL;\n", + "\t\t\t\t}\n", + "\t\t\t\ttry {\n", + "\t\t\t\t\tpoly_d1d1(\n", + "\t\t\t\t\t\t pres, PyArray_SHAPE((PyArrayObject *)pres), (npy_double *)PyArray_DATA((PyArrayObject *)pres)\n", + "\t\t\t\t\t\t, parg, PyArray_SHAPE((PyArrayObject *)parg), (npy_double *)PyArray_DATA((PyArrayObject *)parg)\n", + "\t\t\t\t\t);\n", + "\t\t\t\t\tPy_INCREF(Py_None);\n", + "\t\t\t\t\treturn Py_None;\n", + "\t\t\t\t} catch (...) {\n", + "\t\t\t\t\treturn NULL;\n", + "\t\t\t\t}\n", + "\t\t\t} else\n", + "\t\t\t\tPyErr_Clear();\n", + "\t\t}\n", + "\t\tPyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'res'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'arg'\\np16\\nsg10\\ng11\\nsg12\\nI1\\nsbaa.\", args);\n", + "\t\tif (!signatures) {\n", + "\t\t\tPyErr_SetString(PyExc_ValueError, \"Error building signature string for poly\");\n", + "\t\t\treturn NULL;\n", + "\t\t}\n", + "\t\treturn PyObject_Call(create_signature, signatures, NULL);\n", + "\t}\n", + "\tPyMethodDef polyMethods[] = {\n", + "\t\t{ \"set_create_signature\", (PyCFunction)set_create_signature, METH_VARARGS },\n", + "\t\t{ \"run\", (PyCFunction)run, METH_VARARGS },\n", + "\t\t{ NULL, NULL }\n", + "\t};\n", + "\tPyMODINIT_FUNC initpoly(void) {\n", + "\t\timport_array();\n", + "\t\tPyImport_ImportModule(\"numpy\");\n", + "\t\t(void)Py_InitModule(\"poly\", polyMethods);\n", + "\t}\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + "\tstd::ostringstream buffer;\n", + "\tbuffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + "\tvoid * stack[64];\n", + "\tstd::size_t depth = backtrace(stack, 64);\n", + "\tif (!depth)\n", + "\t\tbuffer << \" \" << std::endl;\n", + "\telse {\n", + "\t\tchar ** symbols = backtrace_symbols(stack, depth);\n", + "\t\tfor (std::size_t i = 1; i < depth; ++i) {\n", + "\t\t\tstd::string symbol = symbols[i];\n", + "\t\t\t\tif (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + "\t\t\t\t\tstd::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + "\t\t\t\t\tint status;\n", + "\t\t\t\t\tchar * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + "\t\t\t\t\tif (!status) {\n", + "\t\t\t\t\t\tbuffer << \" \" \n", + "\t\t\t\t\t\t\t<< symbol.substr(0, 59) \n", + "\t\t\t\t\t\t\t<< demangled\n", + "\t\t\t\t\t\t\t<< symbol.substr(59 + name.size())\n", + "\t\t\t\t\t\t\t<< std::endl;\n", + "\t\t\t\t\t\tfree(demangled);\n", + "\t\t\t\t\t} else\n", + "\t\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", + "\t\t\t\t} else\n", + "\t\t\t\t\tbuffer << \" \" << symbol << std::endl;\n", + "\t\t\t}\n", + "\t\t\tfree(symbols);\n", + "\t\t}\n", + "\t\tstd::cerr << buffer.str();\n", + "\t\tstd::exit(EXIT_FAILURE);\n", + "\t}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pairwise distance" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/pairwise.cpp\n" + ] + } + ], + "source": [ + "%%file src/pairwise.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pairwise_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline void pairwise_d2d2JJ(PyObject * pX,\n", + " npy_intp const * __restrict__ sX,\n", + " npy_double * __restrict__ cX,\n", + " PyObject * pD,\n", + " npy_intp const * __restrict__ sD,\n", + " npy_double * __restrict__ cD,\n", + " npy_int64 const cM,\n", + " npy_int64 const cN);\n", + "\n", + "inline void pairwise_d2d2JJ(PyObject * pX,\n", + " npy_intp const * __restrict__ sX,\n", + " npy_double * __restrict__ cX,\n", + " PyObject * pD,\n", + " npy_intp const * __restrict__ sD,\n", + " npy_double * __restrict__ cD,\n", + " npy_int64 const cM,\n", + " npy_int64 const cN){\n", + "\n", + " npy_double cd = 0.0;\n", + " npy_double ctmp = 0.0;\n", + "\n", + " npy_intp cj;\n", + " npy_intp ck;\n", + " npy_intp x_i_idx;\n", + " npy_intp x_j_idx;\n", + " npy_intp d_i_idx;\n", + " npy_intp const xp = sX[1];\n", + " npy_intp const dp = sD[1];\n", + "\n", + " for (npy_intp ci = 0; ci < cM; ++ci) {\n", + " x_i_idx = ci*xp;\n", + " d_i_idx = ci*dp;\n", + " for (cj = 0; cj < cM; ++cj) {\n", + " cd = 0.0;\n", + " x_j_idx = cj*xp;\n", + " for (ck = 0; ck < cN; ++ck) {\n", + " ctmp = (cX[(x_i_idx + ck)] - cX[(x_j_idx + ck)]);\n", + " cd += (ctmp * ctmp);\n", + " }\n", + " cD[(d_i_idx + cj)] = std::sqrt(cd);\n", + " }\n", + " }\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pX;\n", + " PyObj pD;\n", + " PyObject * pM; npy_int64 cM;\n", + " PyObject * pN; npy_int64 cN;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 4\n", + " and (pX = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pX)\n", + " and PyArray_TYPE((PyArrayObject *)pX) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pX) == 2\n", + " and (pD = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pD)\n", + " and PyArray_TYPE((PyArrayObject *)pD) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pD) == 2\n", + " and (pM = PyTuple_GET_ITEM(args, 2)) and PyLong_CheckExact(pM)\n", + " and (pN = PyTuple_GET_ITEM(args, 3)) and PyLong_CheckExact(pN)\n", + " ) {\n", + " if (!(pX.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pX)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on X!\");\n", + " return NULL;\n", + " }\n", + " if (!(pD.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pD)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on D!\");\n", + " return NULL;\n", + " }\n", + " cM = PyLong_AS_LONG(pM);\n", + " cN = PyLong_AS_LONG(pN);\n", + " try {\n", + " pairwise_d2d2JJ(\n", + " pX, PyArray_SHAPE((PyArrayObject *)pX), (npy_double *)PyArray_DATA((PyArrayObject *)pX)\n", + " , pD, PyArray_SHAPE((PyArrayObject *)pD), (npy_double *)PyArray_DATA((PyArrayObject *)pD)\n", + " , cM\n", + " , cN\n", + " );\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'X'\\np9\\nsS'dtype'\\np10\\nS'float64'\\np11\\nsS'dims'\\np12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\nS'D'\\np16\\nsg10\\ng11\\nsg12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp17\\nRp18\\n(dp19\\ng8\\nS'M'\\np20\\nsg10\\nc__builtin__\\nint\\np21\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp22\\nRp23\\n(dp24\\ng8\\nS'N'\\np25\\nsg10\\ng21\\nsg12\\nI0\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pairwise\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef pairwiseMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + "\n", + " static struct PyModuleDef pairwisemodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pairwise\",\n", + " NULL,\n", + " -1,\n", + " pairwiseMethods\n", + " };\n", + "\n", + "\n", + " PyMODINIT_FUNC PyInit_pairwise(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pairwisemodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Star point spread function CPP" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting src/pdf.cpp\n" + ] + } + ], + "source": [ + "%%file src/pdf.cpp\n", + "#define PY_ARRAY_UNIQUE_SYMBOL pdf_ARRAY_API\n", + "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "struct PyObj {\n", + " typedef PyObject * ptr_t;\n", + " typedef PyArrayObject * arrptr_t;\n", + " PyObj(): dec(false), ptr(NULL) {}\n", + " PyObj(ptr_t p): dec(false), ptr(p) {}\n", + " ~PyObj() { if(dec) Py_DECREF(ptr); }\n", + " PyObj & operator=(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = false; return *this; }\n", + " PyObj & incref(ptr_t p) { if(dec) Py_DECREF(ptr); ptr = p; dec = (p != NULL); return *this; }\n", + " operator bool() const { return ptr; }\n", + " operator ptr_t() const { return ptr; }\n", + " operator arrptr_t() const { return (arrptr_t)ptr; }\n", + " bool dec;\n", + " ptr_t ptr;\n", + "};\n", + "\n", + "inline std::tuple pdf_f2l1d1f2JDd(\n", + " PyObject * pdensity\n", + " , npy_intp const * __restrict__ sdensity\n", + " , npy_float * __restrict__ cdensity\n", + " , PyObject * pdims\n", + " , npy_intp const * __restrict__ sdims\n", + " , npy_int64 * __restrict__ cdims\n", + " , PyObject * pcenter\n", + " , npy_intp const * __restrict__ scenter\n", + " , npy_double * __restrict__ ccenter\n", + " , PyObject * pw2D\n", + " , npy_intp const * __restrict__ sw2D\n", + " , npy_float * __restrict__ cw2D\n", + " , npy_int64 cr50\n", + " , npy_double cb\n", + " , npy_double ca);\n", + "\n", + "inline std::tuple pdf_f2l1d1f2JDd(\n", + " PyObject * pdensity\n", + " , npy_intp const * __restrict__ sdensity\n", + " , npy_float * __restrict__ cdensity\n", + " , PyObject * pdims\n", + " , npy_intp const * __restrict__ sdims\n", + " , npy_int64 * __restrict__ cdims\n", + " , PyObject * pcenter\n", + " , npy_intp const * __restrict__ scenter\n", + " , npy_double * __restrict__ ccenter\n", + " , PyObject * pw2D\n", + " , npy_intp const * __restrict__ sw2D\n", + " , npy_float * __restrict__ cw2D\n", + " , npy_int64 const cr50\n", + " , npy_double const cb\n", + " , npy_double const ca) {\n", + "\n", + " npy_double cdr;\n", + " npy_double c__sum0;\n", + " const npy_double x_center = ccenter[0];\n", + " const npy_double y_center = ccenter[1];\n", + " const npy_intp len_0_sw2D = sw2D[0];\n", + " const npy_intp len_1_sw2D = sw2D[1];\n", + " npy_intp dc[] = {len_0_sw2D, len_1_sw2D};\n", + " PyObject * pc = PyArray_EMPTY(2, dc, NPY_FLOAT64, 0);\n", + " npy_intp * sc = PyArray_SHAPE((PyArrayObject *)pc);\n", + " npy_double * cc = (npy_double *)PyArray_DATA((PyArrayObject *)pc);\n", + "\n", + " npy_intp cy = 0;\n", + " npy_intp i0 = 0;\n", + " npy_intp i1 = 0;\n", + " npy_intp i2 = 0;\n", + " npy_intp i3 = 0;\n", + "\n", + " npy_intp sw2D_i0_idx;\n", + " npy_intp sw2D_i2_idx;\n", + " npy_intp density_x_idx;\n", + "\n", + " auto c__sp0 = ca * ca;\n", + " auto c__sp1 = cr50 * cr50;\n", + " auto c__sp2 = 1.0 / (c__sp0 * c__sp1);\n", + " auto c__sp4 = 0.3183098861846737 * c__sp2 * (-1 + cb);\n", + "\n", + " for (npy_intp cx = 0; cx < cdims[(int)(0)]; ++cx) {\n", + "\n", + " density_x_idx = cx*sdensity[1];\n", + " for (cy = 0; cy < cdims[(int)(1)]; ++cy) {\n", + "\n", + " cdr = std::sqrt(std::pow(cx - x_center, 2) + std::pow(cy - y_center, 2));\n", + " auto c__sp3 = cdr * cdr;\n", + " auto c__sp5 = c__sp4 * std::pow((1 + c__sp2 * c__sp3), -cb);\n", + "\n", + " for (i0 = 0; i0 < len_0_sw2D - 0; ++i0) {\n", + "\n", + " sw2D_i0_idx = (i0)*len_1_sw2D;\n", + " for (i1 = 0; i1 < len_1_sw2D - 0; ++i1) {\n", + " cc[sw2D_i0_idx + i1] = c__sp5 * cw2D[sw2D_i0_idx + i1];\n", + " }\n", + " }\n", + "\n", + " c__sum0 = 0;\n", + " for (i2 = 0; i2 < len_0_sw2D - 0; ++i2) {\n", + "\n", + " sw2D_i2_idx = (i2)*len_1_sw2D;\n", + " for (i3 = 0; i3 < len_1_sw2D - 0; ++i3) {\n", + " c__sum0 += cc[sw2D_i2_idx + i3];\n", + " }\n", + " }\n", + "\n", + " cdensity[(density_x_idx + cy)] = c__sum0;\n", + " }\n", + " }\n", + " return std::make_tuple((PyObject *)pdensity, sdensity, cdensity);\n", + "}\n", + "\n", + "void sighandler(int sig);\n", + "#include \n", + "extern \"C\" {\n", + " PyObject * create_signature;\n", + " struct sigaction slot;\n", + " PyObject * set_create_signature(PyObject * self, PyObject * args) {\n", + " if (!PyArg_ParseTuple(args, \"O\", &create_signature)) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument to set_create_signature!\");\n", + " return NULL;\n", + " }\n", + " Py_INCREF(create_signature);\n", + " memset(&slot, 0, sizeof(slot));\n", + " slot.sa_handler = &sighandler;\n", + " sigaction(SIGSEGV, &slot, NULL);\n", + " sigaction(SIGBUS, &slot, NULL);\n", + " Py_INCREF(Py_None);\n", + " return Py_None;\n", + " }\n", + " PyObject * run(PyObject * self, PyObject * args) {\n", + " {\n", + " PyObj pdensity;\n", + " PyObj pdims;\n", + " PyObj pcenter;\n", + " PyObj pw2D;\n", + " PyObject * pr50; npy_int64 cr50;\n", + " PyObject * pb; npy_double cb;\n", + " PyObject * pa; npy_double ca;\n", + " if (\n", + " PyTuple_CheckExact(args) and PyTuple_GET_SIZE(args) == 7\n", + " and (pdensity = PyTuple_GET_ITEM(args, 0)) and PyArray_CheckExact(pdensity)\n", + " and PyArray_TYPE((PyArrayObject *)pdensity) == NPY_FLOAT32 and PyArray_NDIM((PyArrayObject *)pdensity) == 2\n", + " and (pdims = PyTuple_GET_ITEM(args, 1)) and PyArray_CheckExact(pdims)\n", + " and PyArray_TYPE((PyArrayObject *)pdims) == NPY_INT64 and PyArray_NDIM((PyArrayObject *)pdims) == 1\n", + " and (pcenter = PyTuple_GET_ITEM(args, 2)) and PyArray_CheckExact(pcenter)\n", + " and PyArray_TYPE((PyArrayObject *)pcenter) == NPY_FLOAT64 and PyArray_NDIM((PyArrayObject *)pcenter) == 1\n", + " and (pw2D = PyTuple_GET_ITEM(args, 3)) and PyArray_CheckExact(pw2D)\n", + " and PyArray_TYPE((PyArrayObject *)pw2D) == NPY_FLOAT32 and PyArray_NDIM((PyArrayObject *)pw2D) == 2\n", + " and (pr50 = PyTuple_GET_ITEM(args, 4)) and PyLong_CheckExact(pr50)\n", + " and (pb = PyTuple_GET_ITEM(args, 5)) and PyFloat_CheckExact(pb)\n", + " and (pa = PyTuple_GET_ITEM(args, 6)) and PyArray_IsScalar(pa, Double)\n", + " ) {\n", + " if (!(pdensity.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pdensity)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on density!\");\n", + " return NULL;\n", + " }\n", + " if (!(pdims.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pdims)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on dims!\");\n", + " return NULL;\n", + " }\n", + " if (!(pcenter.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pcenter)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on center!\");\n", + " return NULL;\n", + " }\n", + " if (!(pw2D.incref((PyObject *)PyArray_GETCONTIGUOUS((PyArrayObject *)pw2D)))) {\n", + " PyErr_SetString(PyExc_ValueError, \"Invalid Argument type on w2D!\");\n", + " return NULL;\n", + " }\n", + " cr50 = PyLong_AS_LONG(pr50);\n", + " cb = PyFloat_AS_DOUBLE(pb);\n", + " ca = PyArrayScalar_VAL(pa, Double);\n", + " try {\n", + " PyObject * res = std::get<0>(pdf_f2l1d1f2JDd(\n", + " pdensity, PyArray_SHAPE((PyArrayObject *)pdensity), (npy_float *)PyArray_DATA((PyArrayObject *)pdensity)\n", + " , pdims, PyArray_SHAPE((PyArrayObject *)pdims), (npy_int64 *)PyArray_DATA((PyArrayObject *)pdims)\n", + " , pcenter, PyArray_SHAPE((PyArrayObject *)pcenter), (npy_double *)PyArray_DATA((PyArrayObject *)pcenter)\n", + " , pw2D, PyArray_SHAPE((PyArrayObject *)pw2D), (npy_float *)PyArray_DATA((PyArrayObject *)pw2D)\n", + " , cr50\n", + " , cb\n", + " , ca\n", + " ));\n", + "\n", + " Py_INCREF(res);\n", + " return res;\n", + " } catch (...) {\n", + " return NULL;\n", + " }\n", + " } else\n", + " PyErr_Clear();\n", + " }\n", + " PyObject * signatures = Py_BuildValue(\"(sO)\", \"(lp0\\n(lp1\\nccopy_reg\\n_reconstructor\\np2\\n(chope._ast\\nVariable\\np3\\nc__builtin__\\nobject\\np4\\nNtp5\\nRp6\\n(dp7\\nS'name'\\np8\\nS'density'\\np9\\nsS'dtype'\\np10\\nS'float32'\\np11\\nsS'dims'\\np12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp13\\nRp14\\n(dp15\\ng8\\ng12\\nsg10\\nS'int64'\\np16\\nsg12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp17\\nRp18\\n(dp19\\ng8\\nS'center'\\np20\\nsg10\\nS'float64'\\np21\\nsg12\\nI1\\nsbag2\\n(g3\\ng4\\nNtp22\\nRp23\\n(dp24\\ng8\\nS'w2D'\\np25\\nsg10\\ng11\\nsg12\\nI2\\nsbag2\\n(g3\\ng4\\nNtp26\\nRp27\\n(dp28\\ng8\\nS'r50'\\np29\\nsg10\\nc__builtin__\\nint\\np30\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp31\\nRp32\\n(dp33\\ng8\\nS'b'\\np34\\nsg10\\nc__builtin__\\nfloat\\np35\\nsg12\\nI0\\nsbag2\\n(g3\\ng4\\nNtp36\\nRp37\\n(dp38\\ng8\\nS'a'\\np39\\nsg10\\ng21\\nsg12\\nI0\\nsbaa.\", args);\n", + " if (!signatures) {\n", + " PyErr_SetString(PyExc_ValueError, \"Error building signature string for pdf\");\n", + " return NULL;\n", + " }\n", + " return PyObject_Call(create_signature, signatures, NULL);\n", + " }\n", + "\n", + " PyMethodDef pdfMethods[] = {\n", + " { \"set_create_signature\", set_create_signature, METH_VARARGS, \"signal handler\" },\n", + " { \"run\", run, METH_VARARGS, \"module function\" },\n", + " { NULL, NULL, 0, NULL }\n", + " };\n", + "\n", + " static struct PyModuleDef pdfmodule = {\n", + " PyModuleDef_HEAD_INIT,\n", + " \"pdf\",\n", + " NULL,\n", + " -1,\n", + " pdfMethods\n", + " };\n", + "\n", + " PyMODINIT_FUNC PyInit_pdf(void) {\n", + " import_array();\n", + " PyImport_ImportModule(\"numpy\");\n", + " return PyModule_Create(&pdfmodule);\n", + " }\n", + "}\n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "void sighandler(int sig) {\n", + " std::ostringstream buffer;\n", + " buffer << \"Abort by \" << (sig == SIGSEGV ? \"segfault\" : \"bus error\") << std::endl;\n", + " void * stack[64];\n", + " std::size_t depth = backtrace(stack, 64);\n", + " if (!depth)\n", + " buffer << \" \" << std::endl;\n", + " else {\n", + " char ** symbols = backtrace_symbols(stack, depth);\n", + " for (std::size_t i = 1; i < depth; ++i) {\n", + " std::string symbol = symbols[i];\n", + " if (symbol.find_first_of(' ', 59) != std::string::npos) {\n", + " std::string name = symbol.substr(59, symbol.find_first_of(' ', 59) - 59);\n", + " int status;\n", + " char * demangled = abi::__cxa_demangle(name.c_str(), NULL, NULL, &status);\n", + " if (!status) {\n", + " buffer << \" \"\n", + " << symbol.substr(0, 59)\n", + " << demangled\n", + " << symbol.substr(59 + name.size())\n", + " << std::endl;\n", + " free(demangled);\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " } else\n", + " buffer << \" \" << symbol << std::endl;\n", + " }\n", + " free(symbols);\n", + " }\n", + " std::cerr << buffer.str();\n", + " std::exit(EXIT_FAILURE);\n", + " }" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python helper module" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting native_util.py\n" + ] + } + ], + "source": [ + "%%file native_util.py\n", + "import importlib\n", + "import os\n", + "import glob\n", + "import sys\n", + "\n", + "from numpy.distutils.misc_util import get_numpy_include_dirs\n", + "import setuptools\n", + "from os import listdir\n", + "# import tempfile\n", + "from hope import config\n", + "\n", + "try:\n", + " # python 3\n", + " import io\n", + " file = io.IOBase\n", + "except ImportError:\n", + " pass\n", + "\n", + "\n", + "def load(name):\n", + " compile(name, \"./src\")\n", + " module = importlib.import_module(name)\n", + " # module = __import__(name, globals(), locals(), [], -1)\n", + " return module\n", + "\n", + "\n", + "\n", + "def compile(name, src_folder, target_folder = \"./\"):\n", + " localfilename =os.path.join(src_folder, name)\n", + " \n", + " outfile, stdout, stderr, argv = None, None, None, sys.argv\n", + " try:\n", + " sys.stdout.flush(), sys.stderr.flush()\n", + " outpath = os.path.join(target_folder, \"{0}.out\".format(localfilename))\n", + " if os.path.exists(outpath):\n", + " os.remove(outpath)\n", + " \n", + " so_path = os.path.join(target_folder, \"{0}.so\".format(name))\n", + " if os.path.exists(so_path):\n", + " os.remove(so_path)\n", + " \n", + " outfile = open(outpath, 'w')\n", + " \n", + " try:\n", + " sys.stdout.fileno()\n", + " sys.stderr.fileno()\n", + " have_fileno = True\n", + " except OSError:\n", + " have_fileno = False\n", + " \n", + " if have_fileno and isinstance(sys.stdout, file) and isinstance(sys.stdout, file):\n", + " stdout, stderr = os.dup(sys.stdout.fileno()), os.dup(sys.stderr.fileno())\n", + " os.dup2(outfile.fileno(), sys.stdout.fileno())\n", + " os.dup2(outfile.fileno(), sys.stderr.fileno())\n", + " else:\n", + " stdout, stderr = sys.stdout, sys.stderr\n", + " sys.stdout, sys.stderr = outfile, outfile\n", + " try:\n", + " sources = \"./{0}.cpp\".format(localfilename)\n", + " sys.argv = [\"\", \"build_ext\",\n", + " \"-b\", target_folder, #--build-lib (-b) directory for compiled extension modules\n", + " \"-t\", \".\" #--build-temp - a rel path will result in a dir structure of -b at the cur position \n", + " ]\n", + " \n", + " localfilename = str(localfilename)\n", + " sources = str(sources)\n", + " \n", + " setuptools.setup( \\\n", + " name = name\\\n", + " , ext_modules = [setuptools.Extension( \\\n", + " name \\\n", + " , sources = [sources] \\\n", + " , extra_compile_args = config.cxxflags \\\n", + " )] \\\n", + " , include_dirs = get_numpy_include_dirs() \\\n", + " )\n", + " except SystemExit as e:\n", + " print(sys.stderr.write(str(e)))\n", + " sys.stdout.flush(), sys.stderr.flush()\n", + " finally:\n", + " if isinstance(stdout, int):\n", + " os.dup2(stdout, sys.stdout.fileno()), os.close(stdout)\n", + " elif not stdout is None:\n", + " sys.stdout = stdout\n", + " if isinstance(stderr, int):\n", + " os.dup2(stderr, sys.stderr.fileno()), os.close(stderr)\n", + " elif not stderr is None:\n", + " sys.stderr = stderr\n", + " if isinstance(outfile, file):\n", + " outfile.close()\n", + " sys.argv = argv\n", + " \n", + " with open(outpath) as outfile:\n", + " out = outfile.read()\n", + " \n", + " modules = glob.glob(os.path.join(target_folder, \"{}*.so\".format(name)))\n", + " \n", + " if not modules or out.find(\"error:\") > -1:\n", + " print(out)\n", + " raise Exception(\"Error compiling function {0} (compiled to {1})\".format(localfilename, target_folder))\n", + " \n", + " if out.find(\"warning:\") > -1:\n", + " import warnings\n", + " warnings.warn(\"A warning has been issued during compilation:\\n%s\"%out)\n", + " \n", + " print(out)\n", + "\n", + "\n", + "def compile_all():\n", + " src_folder = \"./src\"\n", + " func_names = (src_file.split(\".cpp\")[0] for src_file in listdir(src_folder) if src_file.endswith(\".cpp\"))\n", + " for func_name in func_names:\n", + " compile(func_name, src_folder)\n", + " \n", + " \n", + "if __name__ == '__main__':\n", + " compile_all()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting util.py\n" + ] + } + ], + "source": [ + "%%file util.py\n", + "# Copyright (C) 2014 ETH Zurich, Institute for Astronomy\n", + "\n", + "'''\n", + "Created on Aug 4, 2014\n", + "\n", + "author: jakeret\n", + "'''\n", + "from __future__ import print_function, division, absolute_import, unicode_literals\n", + "import math\n", + "\n", + "def perf_comp_data(func_list, data_list, rep=5, number=1, extra_setup=None):\n", + " ''' Function to compare the performance of different functions.\n", + " \n", + " Parameters\n", + " ==========\n", + " func_list : list\n", + " list with function names as strings\n", + " data_list : list\n", + " list with data set names as strings\n", + " rep : int\n", + " number of repetitions of the whole comparison\n", + " number : int\n", + " number of executions for every function\n", + " '''\n", + " from timeit import repeat\n", + " res_list = {}\n", + " for name in enumerate(func_list):\n", + " if data_list is None:\n", + " stmt = \"%s()\"%(name[1])\n", + " setup = \"from __main__ import %s\"%(name[1]) \n", + " else:\n", + " stmt = \"%s(%s)\"%(name[1], data_list[name[0]])\n", + " setup = \"from __main__ import %s, %s\"%(name[1], data_list[name[0]])\n", + " if extra_setup is not None:\n", + " stmt = extra_setup + \"; \" + stmt\n", + " \n", + " results = repeat(stmt=stmt, setup=setup, repeat=rep, number=number)\n", + " \n", + " res_list[name[1]] = (median(results), min(results))\n", + " \n", + "# res_sort = sorted(res_list.iteritems(), key=lambda (k, v): (v, k))\n", + " res_sort = sorted(iter(res_list.items()), key=lambda k_v: (k_v[1], k_v[0]))\n", + " for func, (av_time, min_time) in res_sort:\n", + " rel = av_time / res_sort[0][1][0]\n", + " print('function: {0!s:20}, av. time sec: {1:>12.8f}, min. time sec: {2:>12.8f}, relative: {3:>9.1f}'.format(func, av_time, min_time, rel))\n", + "\n", + "def median(x):\n", + " s_x = sorted(x)\n", + " return (s_x[int(math.floor((len(s_x)-1)/2))] + s_x[int(math.ceil((len(s_x)-1)/2))])/2" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/numexpr.ipynb b/benchmarks/numexpr.ipynb index 48c37c2..da1fa20 100644 --- a/benchmarks/numexpr.ipynb +++ b/benchmarks/numexpr.ipynb @@ -1,665 +1,612 @@ { - "metadata": { - "name": "", - "signature": "sha256:f51733b3c4c4439e321dc29d5ba36f149a1a77c8e879a9549b540aed6dbc3edf" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import hope\n", - "hope.config.optimize = True\n", - "hope.config.verbose = True\n", - "hope.config.keeptemp = True\n", - "import numba\n", - "import numpy as np\n", - "import numexpr as ne\n", - "\n", - "from util import perf_comp_data\n", - "from native_util import load\n", - "%load_ext cythonmagic\n", - "%load_ext version_information\n", - "%version_information numpy, Cython, numba, hope, numexpr" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "
SoftwareVersion
Python2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
IPython1.1.0
OSposix [darwin]
numpy1.8.1
Cython0.20.2
numba0.13.3
hope0.3.0
numexpr2.4
Thu Sep 04 15:13:34 2014 CEST
" - ], - "json": [ - "{\"Software versions\": [{\"version\": \"2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\", \"module\": \"Python\"}, {\"version\": \"1.1.0\", \"module\": \"IPython\"}, {\"version\": \"posix [darwin]\", \"module\": \"OS\"}, {\"version\": \"1.8.1\", \"module\": \"numpy\"}, {\"version\": \"0.20.2\", \"module\": \"Cython\"}, {\"version\": \"0.13.3\", \"module\": \"numba\"}, {\"version\": \"0.3.0\", \"module\": \"hope\"}, {\"version\": \"2.4\", \"module\": \"numexpr\"}]}" - ], - "latex": [ - "\\begin{tabular}{|l|l|}\\hline\n", - "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", - "Python & 2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] \\\\ \\hline\n", - "IPython & 1.1.0 \\\\ \\hline\n", - "OS & posix [darwin] \\\\ \\hline\n", - "numpy & 1.8.1 \\\\ \\hline\n", - "Cython & 0.20.2 \\\\ \\hline\n", - "numba & 0.13.3 \\\\ \\hline\n", - "hope & 0.3.0 \\\\ \\hline\n", - "numexpr & 2.4 \\\\ \\hline\n", - "\\hline \\multicolumn{2}{|l|}{Thu Sep 04 15:13:34 2014 CEST} \\\\ \\hline\n", - "\\end{tabular}\n" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "Software versions\n", - "Python 2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\n", - "IPython 1.1.0\n", - "OS posix [darwin]\n", - "numpy 1.8.1\n", - "Cython 0.20.2\n", - "numba 0.13.3\n", - "hope 0.3.0\n", - "numexpr 2.4\n", - "Thu Sep 04 15:13:34 2014 CEST" - ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Python version\n", - "\n", - "def ln_python(X, Y):\n", - " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Python version\n", - "\n", - "def ln_python_exp(X, Y):\n", - " x = (X - 1)\n", - " x2 = x*x\n", - " x4 = x2*x2\n", - " x6 = x4*x2\n", - " x8 = x4*x4\n", - " Y[:] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "prompt_number": 3 - }, + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "# NumExpr version\n", - "def ln_numexpr(X, Y):\n", - " Y[:] = ne.evaluate(\"(X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\")\n" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Hope version\n", - "@hope.jit\n", - "def ln_hope(X, Y):\n", - " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "output_type": "stream", - "stream": "stderr", - "text": [ - "/Users/jakeret/workspace/hope/hope/jit.py:128: UserWarning: Recompiling... Reason: State is inconsistent with config. Inconsistent state key: [optimize].\n", - " warnings.warn(\"Recompiling... Reason: {0}\".format(le))\n" + "data": { + "application/json": { + "Software versions": [ + { + "module": "Python", + "version": "3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]" + }, + { + "module": "IPython", + "version": "6.1.0" + }, + { + "module": "OS", + "version": "Darwin 15.6.0 x86_64 i386 64bit" + }, + { + "module": "numpy", + "version": "1.13.1" + }, + { + "module": "Cython", + "version": "0.26" + }, + { + "module": "numba", + "version": "0.34.0" + }, + { + "module": "hope", + "version": "0.6.1" + }, + { + "module": "numexpr", + "version": "2.6.2" + } ] - } - ], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Hope version\n", - "\n", - "import hope\n", - "hope.config.optimize = False\n", - "@hope.jit\n", - "def ln_hope_exp(X, Y):\n", - " x = (X - 1)\n", - " x2 = x*x\n", - " x4 = x2*x2\n", - " x6 = x4*x2\n", - " x8 = x4*x4\n", - " Y[:] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# numba version\n", - "\n", - "@numba.jit\n", - "def ln_numba(X, Y):\n", - " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# numba version\n", - "\n", - "import numba\n", - "\n", - "@numba.jit\n", - "def ln_numba_exp(X, Y):\n", - " x = (X - 1)\n", - " x2 = x*x\n", - " x4 = x2*x2\n", - " x6 = x4*x2\n", - " x8 = x4*x4\n", - " Y[:] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } + }, + "text/html": [ + "
SoftwareVersion
Python3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
IPython6.1.0
OSDarwin 15.6.0 x86_64 i386 64bit
numpy1.13.1
Cython0.26
numba0.34.0
hope0.6.1
numexpr2.6.2
Mon Sep 04 15:24:42 2017 CEST
" + ], + "text/latex": [ + "\\begin{tabular}{|l|l|}\\hline\n", + "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", + "Python & 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] \\\\ \\hline\n", + "IPython & 6.1.0 \\\\ \\hline\n", + "OS & Darwin 15.6.0 x86\\_64 i386 64bit \\\\ \\hline\n", + "numpy & 1.13.1 \\\\ \\hline\n", + "Cython & 0.26 \\\\ \\hline\n", + "numba & 0.34.0 \\\\ \\hline\n", + "hope & 0.6.1 \\\\ \\hline\n", + "numexpr & 2.6.2 \\\\ \\hline\n", + "\\hline \\multicolumn{2}{|l|}{Mon Sep 04 15:24:42 2017 CEST} \\\\ \\hline\n", + "\\end{tabular}\n" + ], + "text/plain": [ + "Software versions\n", + "Python 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n", + "IPython 6.1.0\n", + "OS Darwin 15.6.0 x86_64 i386 64bit\n", + "numpy 1.13.1\n", + "Cython 0.26\n", + "numba 0.34.0\n", + "hope 0.6.1\n", + "numexpr 2.6.2\n", + "Mon Sep 04 15:24:42 2017 CEST" + ] }, - "outputs": [], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%load_ext cythonmagic" - ], - "language": "python", + "execution_count": 1, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "The cythonmagic extension is already loaded. To reload it, use:\n", - " %reload_ext cythonmagic\n" - ] - } - ], - "prompt_number": 9 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import hope\n", + "hope.config.optimize = True\n", + "hope.config.verbose = True\n", + "hope.config.keeptemp = True\n", + "import numba\n", + "import numpy as np\n", + "import numexpr as ne\n", + "\n", + "from util import perf_comp_data\n", + "from native_util import load\n", + "%load_ext Cython\n", + "%load_ext version_information\n", + "%version_information numpy, Cython, numba, hope, numexpr" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# Python version\n", + "\n", + "def ln_python(X, Y):\n", + " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# Python version\n", + "\n", + "def ln_python_exp(X, Y):\n", + " x = (X - 1)\n", + " x2 = x*x\n", + " x4 = x2*x2\n", + " x6 = x4*x2\n", + " x8 = x4*x4\n", + " Y[:] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# NumExpr version\n", + "def ln_numexpr(X, Y):\n", + " Y[:] = ne.evaluate(\"(X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "\n", - "cimport cython\n", - "\n", - "cimport cython\n", - "import numpy as np\n", - "cimport numpy as np\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def ln_cython(np.ndarray[np.double_t, ndim=1] X, np.ndarray[np.double_t, ndim=1] Y):\n", - " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n", - "\n", - " \n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def ln_cython_exp(np.ndarray[np.float_t, ndim=1] X, np.ndarray[np.float_t, ndim=1] Y):\n", - " cdef np.ndarray[np.double_t, ndim=1] x = (X - 1)\n", - " cdef np.ndarray[np.double_t, ndim=1] x2 = x*x\n", - " cdef np.ndarray[np.double_t, ndim=1] x4 = x2*x2\n", - " cdef np.ndarray[np.double_t, ndim=1] x6 = x4*x2\n", - " cdef np.ndarray[np.double_t, ndim=1] x8 = x4*x4\n", - " Y[:] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 10 - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/uweschmitt/Projects/hope/hope/jit.py:112: UserWarning: Recompiling... Reason: State is inconsistent with config. Inconsistent state key: [optimize].\n", + " warnings.warn(\"Recompiling... Reason: {0}\".format(le))\n" + ] + } + ], + "source": [ + "# Hope version\n", + "@hope.jit\n", + "def ln_hope(X, Y):\n", + " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# Hope version\n", + "\n", + "import hope\n", + "hope.config.optimize = False\n", + "@hope.jit\n", + "def ln_hope_exp(X, Y):\n", + " x = (X - 1)\n", + " x2 = x*x\n", + " x4 = x2*x2\n", + " x6 = x4*x2\n", + " x8 = x4*x4\n", + " Y[:] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# numba version\n", + "\n", + "@numba.jit\n", + "def ln_numba(X, Y):\n", + " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# numba version\n", + "\n", + "import numba\n", + "\n", + "@numba.jit\n", + "def ln_numba_exp(X, Y):\n", + " x = (X - 1)\n", + " x2 = x*x\n", + " x4 = x2*x2\n", + " x6 = x4*x2\n", + " x8 = x4*x4\n", + " Y[:] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%%cython\n", + "\n", + "cimport cython\n", + "\n", + "cimport cython\n", + "import numpy as np\n", + "cimport numpy as np\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "def ln_cython(np.ndarray[np.double_t, ndim=1] X, np.ndarray[np.double_t, ndim=1] Y):\n", + " cdef size_t i, n\n", + " cdef double x\n", + " n = len(X)\n", + " cdef double *xx = X.data\n", + " cdef double *yy = Y.data\n", + " for i in range(n):\n", + " x = xx[i] \n", + " yy[i] = (x-1) - (x-1)**2 / 2 + (x-1)**3 / 3 - (x-1)**4 / 4 + (x-1)**5 / 5 - (x-1)**6 / 6 + (x-1)**7 / 7 - (x-1)**8 / 8 + (x-1)**9 / 9\n", + "\n", + " \n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "def ln_cython_exp(np.ndarray[np.float_t, ndim=1] X, np.ndarray[np.float_t, ndim=1] Y):\n", + " cdef size_t i, n\n", + " cdef double x, x2, x4, x6, x8\n", + " cdef double *xx = X.data\n", + " cdef double *yy = Y.data\n", + " n = len(X)\n", + " for i in range(n):\n", + " x = xx[i] - 1\n", + " x2 = x * x\n", + " x4 = x2 * x2\n", + " x6 = x2 * x4\n", + " x8 = x4 * x4\n", + " yy[i] = x - x2 / 2 + x * x2 / 3 - x4 / 4 + x * x4 / 5 - x6 / 6 + x6 * x / 7 - x8 / 8 + x8 * x / 9 \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from native_util import load\n", - "native_ln_mod = load(\"ln\")\n", - "ln_native = native_ln_mod.run\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "running build_ext\n", + "building 'ln' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "native_ln_opt_mod = load(\"ln_opt\")\n", - "ln_native_opt = native_ln_opt_mod.run\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: ././src/ln.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g ./src/ln.o -o ./ln.cpython-35m-darwin.so\n", "\n", - "native_ln_exp_mod = load(\"ln_exp\")\n", - "ln_native_exp = native_ln_exp_mod.run\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'ln' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/ln.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/ln.o -o ./ln.so\n", - "\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'ln_opt' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/ln_opt.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/ln_opt.o -o ./ln_opt.so\n", - "\n" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'ln_exp' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/ln_exp.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/ln_exp.o -o ./ln_exp.so\n", - "\n" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Hope version - optimized\n", - "\n", - "import hope\n", - "hope.config.optimize = True\n", + "running build_ext\n", + "building 'ln_opt' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "@hope.jit\n", - "def ln_hope_opt(X, Y):\n", - " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: ././src/ln_opt.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g ./src/ln_opt.o -o ./ln_opt.cpython-35m-darwin.so\n", "\n", + "running build_ext\n", + "building 'ln_exp' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "hope.config.optimize = False" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "notes" - } - }, - "outputs": [], - "prompt_number": 13 - }, + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: ././src/ln_exp.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g ./src/ln_exp.o -o ./ln_exp.cpython-35m-darwin.so\n", + "\n" + ] + } + ], + "source": [ + "from native_util import load\n", + "native_ln_mod = load(\"ln\")\n", + "ln_native = native_ln_mod.run\n", + "\n", + "native_ln_opt_mod = load(\"ln_opt\")\n", + "ln_native_opt = native_ln_opt_mod.run\n", + "\n", + "native_ln_exp_mod = load(\"ln_exp\")\n", + "ln_native_exp = native_ln_exp_mod.run\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "notes" + } + }, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import numpy as np\n", - "\n", - "X = np.random.random(10000).astype(np.float64)\n", - "Y = np.ones_like(X)" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [], - "prompt_number": 15 - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/uweschmitt/Projects/hope/hope/jit.py:112: UserWarning: Recompiling... Reason: State is inconsistent with config. Inconsistent state key: [optimize].\n", + " warnings.warn(\"Recompiling... Reason: {0}\".format(le))\n" + ] + } + ], + "source": [ + "# Hope version - optimized\n", + "\n", + "import hope\n", + "hope.config.optimize = True\n", + "\n", + "@hope.jit\n", + "def ln_hope_opt(X, Y):\n", + " Y[:] = (X-1) - (X-1)**2 / 2 + (X-1)**3 / 3 - (X-1)**4 / 4 + (X-1)**5 / 5 - (X-1)**6 / 6 + (X-1)**7 / 7 - (X-1)**8 / 8 + (X-1)**9 / 9\n", + "\n", + "\n", + "hope.config.optimize = False" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "X = np.random.random(10000).astype(np.float64)\n", + "Y = np.ones_like(X)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "Y1 = np.ones_like(X)\n", - "Y2 = np.ones_like(X)\n", - "Y3 = np.ones_like(X)\n", - "Y4 = np.ones_like(X)\n", - "Y5 = np.ones_like(X)\n", - "Y6 = np.ones_like(X)\n", - "Y7 = np.ones_like(X)\n", - "Y8 = np.ones_like(X)\n", - "Y9 = np.ones_like(X)\n", - "Y10 = np.ones_like(X)\n", - "Y11 = np.ones_like(X)\n", - "Y12 = np.ones_like(X)\n", - "Y13 = np.ones_like(X)\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "Compiling following functions:\n", + "ln_hope(float64^1 X, float64^1 Y)\n", + "running build_ext\n", + "building 'ln_hope_f15670420910980a71b044ad212142e5c0bffbce3030fa3603b54df8_0' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch i386 -arch x86_64 -g\n", "\n", - "ln_python(X, Y1)\n", - "ln_python_exp(X, Y2)\n", - "ln_cython(X, Y3)\n", - "ln_cython_exp(X, Y4)\n", - "ln_numexpr(X, Y5)\n", - "ln_hope(X, Y6)\n", - "ln_hope_exp(X, Y7)\n", - "ln_numba(X, Y8)\n", - "ln_numba_exp(X, Y9)\n", - "ln_native(X, Y10)\n", - "ln_native_opt(X, Y11)\n", - "ln_native_exp(X, Y12)\n", - "ln_hope_opt(X, Y13)\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hope8ltuei58/ln_hope_f15670420910980a71b044ad212142e5c0bffbce3030fa3603b54df8_0.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hope8ltuei58/ln_hope_f15670420910980a71b044ad212142e5c0bffbce3030fa3603b54df8_0.o -o /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hope8ltuei58/ln_hope_f15670420910980a71b044ad212142e5c0bffbce3030fa3603b54df8_0.cpython-35m-darwin.so\n", "\n", - "assert np.allclose(Y1,Y2, 1E-10)\n", - "assert np.allclose(Y1,Y3, 1E-10)\n", - "assert np.allclose(Y1,Y4, 1E-10)\n", - "assert np.allclose(Y1,Y5, 1E-10)\n", - "assert np.allclose(Y1,Y6, 1E-10)\n", - "assert np.allclose(Y1,Y7, 1E-10)\n", - "assert np.allclose(Y1,Y8, 1E-10)\n", - "assert np.allclose(Y1,Y9, 1E-10)\n", - "assert np.allclose(Y1,Y10, 1E-10)\n", - "assert np.allclose(Y1,Y11, 1E-10)\n", - "assert np.allclose(Y1,Y12, 1E-10)\n", - "assert np.allclose(Y1,Y13, 1E-10)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 17 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "import numexpr as ne\n", + "Compiling following functions:\n", + "ln_hope_opt(float64^1 X, float64^1 Y)\n", + "running build_ext\n", + "building 'ln_hope_opt_e61495c068774ff7cc57eca53040c8172f643a2ae5e21fb9ddd84b2c_0' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch i386 -arch x86_64 -g\n", "\n", - "print \"python\"\n", - "%timeit ln_python(X, Y)\n", - "%timeit ln_python_exp(X, Y)\n", - "print \"numexpr (1)\"\n", - "ne.set_num_threads(1)\n", - "%timeit ln_numexpr(X, Y)\n", - "print \"numexpr ({0})\".format(ne.detect_number_of_cores())\n", - "ne.set_num_threads(ne.detect_number_of_cores())\n", - "%timeit ln_numexpr(X, Y)\n", - "print \"hope\"\n", - "%timeit ln_hope(X, Y)\n", - "%timeit ln_hope_exp(X, Y)\n", - "%timeit ln_hope_opt(X, Y)\n", - "print \"cython\"\n", - "%timeit ln_cython(X, Y)\n", - "%timeit ln_cython_exp(X, Y)\n", - "print \"numba\"\n", - "%timeit ln_numba(X, Y)\n", - "%timeit ln_numba_exp(X, Y)\n", - "print \"native\"\n", - "%timeit ln_native(X, Y)\n", - "%timeit ln_native_opt(X, Y)\n", - "%timeit ln_native_exp(X, Y)\n" - ], - "language": "python", - "metadata": { - "slideshow": { - "slide_type": "slide" - } - }, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "python\n", - "100 loops, best of 3: 2.4 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1000 loops, best of 3: 299 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numexpr (1)\n", - "1000 loops, best of 3: 400 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numexpr (8)\n", - "1000 loops, best of 3: 200 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope\n", - "10000 loops, best of 3: 128 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1000 loops, best of 3: 212 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10000 loops, best of 3: 128 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "cython\n", - "100 loops, best of 3: 2.4 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1000 loops, best of 3: 305 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numba\n", - "100 loops, best of 3: 2.41 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "1000 loops, best of 3: 305 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "native\n", - "100 loops, best of 3: 2.12 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10000 loops, best of 3: 128 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "10000 loops, best of 3: 106 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 18 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from util import perf_comp_data" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 19 - }, + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hopehhalgg0h/ln_hope_opt_e61495c068774ff7cc57eca53040c8172f643a2ae5e21fb9ddd84b2c_0.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hopehhalgg0h/ln_hope_opt_e61495c068774ff7cc57eca53040c8172f643a2ae5e21fb9ddd84b2c_0.o -o /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hopehhalgg0h/ln_hope_opt_e61495c068774ff7cc57eca53040c8172f643a2ae5e21fb9ddd84b2c_0.cpython-35m-darwin.so\n", + "\n" + ] + } + ], + "source": [ + "Y1 = np.ones_like(X)\n", + "Y2 = np.ones_like(X)\n", + "Y3 = np.ones_like(X)\n", + "Y4 = np.ones_like(X)\n", + "Y5 = np.ones_like(X)\n", + "Y6 = np.ones_like(X)\n", + "Y7 = np.ones_like(X)\n", + "Y8 = np.ones_like(X)\n", + "Y9 = np.ones_like(X)\n", + "Y10 = np.ones_like(X)\n", + "Y11 = np.ones_like(X)\n", + "Y12 = np.ones_like(X)\n", + "Y13 = np.ones_like(X)\n", + "\n", + "ln_python(X, Y1)\n", + "ln_python_exp(X, Y2)\n", + "ln_cython(X, Y3)\n", + "ln_cython_exp(X, Y4)\n", + "ln_numexpr(X, Y5)\n", + "ln_hope(X, Y6)\n", + "ln_hope_exp(X, Y7)\n", + "ln_numba(X, Y8)\n", + "ln_numba_exp(X, Y9)\n", + "ln_native(X, Y10)\n", + "ln_native_opt(X, Y11)\n", + "ln_native_exp(X, Y12)\n", + "ln_hope_opt(X, Y13)\n", + "\n", + "assert np.allclose(Y1,Y2, 1E-10)\n", + "assert np.allclose(Y1,Y3, 1E-10)\n", + "assert np.allclose(Y1,Y4, 1E-10)\n", + "assert np.allclose(Y1,Y5, 1E-10)\n", + "assert np.allclose(Y1,Y6, 1E-10)\n", + "assert np.allclose(Y1,Y7, 1E-10)\n", + "assert np.allclose(Y1,Y8, 1E-10)\n", + "assert np.allclose(Y1,Y9, 1E-10)\n", + "assert np.allclose(Y1,Y10, 1E-10)\n", + "assert np.allclose(Y1,Y11, 1E-10)\n", + "assert np.allclose(Y1,Y12, 1E-10)\n", + "assert np.allclose(Y1,Y13, 1E-10)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "func_list = [\"ln_python\", \"ln_python_exp\", \n", - " \"ln_numexpr\", \n", - " \"ln_hope\", \"ln_hope_exp\", \"ln_hope_opt\", \n", - " \"ln_cython\", \"ln_cython_exp\", \n", - " \"ln_numba\", \"ln_numba_exp\", \n", - " \"ln_native\", \"ln_native_opt\", \"ln_native_exp\", ]\n", - "perf_comp_data(func_list,\n", - " len(func_list)*[\"X, Y\"], rep=100)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: ln_native_exp , av. time sec: 0.00010705, min. time sec: 0.00010586, relative: 1.0\n", - "function: ln_hope_opt , av. time sec: 0.00012398, min. time sec: 0.00012398, relative: 1.2\n", - "function: ln_hope , av. time sec: 0.00012422, min. time sec: 0.00012398, relative: 1.2\n", - "function: ln_native_opt , av. time sec: 0.00012803, min. time sec: 0.00012708, relative: 1.2\n", - "function: ln_hope_exp , av. time sec: 0.00020707, min. time sec: 0.00020695, relative: 1.9\n", - "function: ln_numexpr , av. time sec: 0.00021243, min. time sec: 0.00018501, relative: 2.0\n", - "function: ln_python_exp , av. time sec: 0.00029302, min. time sec: 0.00029206, relative: 2.7\n", - "function: ln_numba_exp , av. time sec: 0.00030351, min. time sec: 0.00029993, relative: 2.8\n", - "function: ln_cython_exp , av. time sec: 0.00030696, min. time sec: 0.00029683, relative: 2.9\n", - "function: ln_native , av. time sec: 0.00215054, min. time sec: 0.00208783, relative: 20.1\n", - "function: ln_cython , av. time sec: 0.00241804, min. time sec: 0.00235510, relative: 22.6\n", - "function: ln_numba , av. time sec: 0.00241804, min. time sec: 0.00237322, relative: 22.6\n", - "function: ln_python , av. time sec: 0.00243747, min. time sec: 0.00235200, relative: 22.8\n" - ] - } - ], - "prompt_number": 20 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "python\n", + "2.46 ms ± 25.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "304 µs ± 12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "numexpr (1)\n", + "442 µs ± 7.12 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "numexpr (8)\n", + "211 µs ± 7.66 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "hope\n", + "2.37 ms ± 59.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "124 µs ± 2.12 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "2.45 ms ± 24.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "cython\n", + "2.24 ms ± 87.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "120 µs ± 3.78 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "numba\n", + "130 µs ± 1.64 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "282 µs ± 3.52 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "native\n", + "2.4 ms ± 73.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "74 µs ± 1.19 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "122 µs ± 1.52 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" + ] + } + ], + "source": [ + "import numexpr as ne\n", + "\n", + "print(\"python\")\n", + "%timeit ln_python(X, Y)\n", + "%timeit ln_python_exp(X, Y)\n", + "print(\"numexpr (1)\")\n", + "ne.set_num_threads(1)\n", + "%timeit ln_numexpr(X, Y)\n", + "print(\"numexpr ({0})\".format(ne.detect_number_of_cores()))\n", + "ne.set_num_threads(ne.detect_number_of_cores())\n", + "%timeit ln_numexpr(X, Y)\n", + "print(\"hope\")\n", + "%timeit ln_hope(X, Y)\n", + "%timeit ln_hope_exp(X, Y)\n", + "%timeit ln_hope_opt(X, Y)\n", + "print(\"cython\")\n", + "%timeit ln_cython(X, Y)\n", + "%timeit ln_cython_exp(X, Y)\n", + "print(\"numba\")\n", + "%timeit ln_numba(X, Y)\n", + "%timeit ln_numba_exp(X, Y)\n", + "print(\"native\")\n", + "%timeit ln_native(X, Y)\n", + "%timeit ln_native_opt(X, Y)\n", + "%timeit ln_native_exp(X, Y)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from util import perf_comp_data" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "function: ln_native_opt , av. time sec: 0.00006836, min. time sec: 0.00006819, relative: 1.0\n", + "function: ln_cython_exp , av. time sec: 0.00010206, min. time sec: 0.00010199, relative: 1.5\n", + "function: ln_native_exp , av. time sec: 0.00011374, min. time sec: 0.00011370, relative: 1.7\n", + "function: ln_numba , av. time sec: 0.00011900, min. time sec: 0.00011891, relative: 1.7\n", + "function: ln_hope_exp , av. time sec: 0.00013583, min. time sec: 0.00011382, relative: 2.0\n", + "function: ln_numexpr , av. time sec: 0.00018525, min. time sec: 0.00017029, relative: 2.7\n", + "function: ln_numba_exp , av. time sec: 0.00025554, min. time sec: 0.00025503, relative: 3.7\n", + "function: ln_python_exp , av. time sec: 0.00028491, min. time sec: 0.00026110, relative: 4.2\n", + "function: ln_cython , av. time sec: 0.00203083, min. time sec: 0.00191422, relative: 29.7\n", + "function: ln_hope_opt , av. time sec: 0.00220507, min. time sec: 0.00220174, relative: 32.3\n", + "function: ln_native , av. time sec: 0.00220511, min. time sec: 0.00220164, relative: 32.3\n", + "function: ln_hope , av. time sec: 0.00221205, min. time sec: 0.00220165, relative: 32.4\n", + "function: ln_python , av. time sec: 0.00238910, min. time sec: 0.00224400, relative: 34.9\n" + ] } ], - "metadata": {} + "source": [ + "func_list = [\"ln_python\", \"ln_python_exp\", \n", + " \"ln_numexpr\", \n", + " \"ln_hope\", \"ln_hope_exp\", \"ln_hope_opt\", \n", + " \"ln_cython\", \"ln_cython_exp\", \n", + " \"ln_numba\", \"ln_numba_exp\", \n", + " \"ln_native\", \"ln_native_opt\", \"ln_native_exp\", ]\n", + "perf_comp_data(func_list,\n", + " len(func_list)*[\"X, Y\"], rep=100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } - ] -} \ No newline at end of file + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/pairwise.ipynb b/benchmarks/pairwise.ipynb index 98acb33..b77378e 100644 --- a/benchmarks/pairwise.ipynb +++ b/benchmarks/pairwise.ipynb @@ -1,385 +1,390 @@ { - "metadata": { - "name": "", - "signature": "sha256:1fb785098fbe4c8872abc9c10232ddb25cc7c2e7aa992b02730c9fd63ff5b18f" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import hope\n", - "hope.config.optimize = True\n", - "hope.config.verbose = True\n", - "hope.config.keeptemp = True\n", - "import numba\n", - "import numpy as np\n", - "from util import perf_comp_data\n", - "from native_util import load\n", - "%load_ext cythonmagic\n", - "%load_ext version_information\n", - "%version_information numpy, Cython, numba, hope" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "
SoftwareVersion
Python2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
IPython1.1.0
OSposix [darwin]
numpy1.8.1
Cython0.20.2
numba0.13.3
hope0.3.0
Thu Sep 04 15:18:18 2014 CEST
" - ], - "json": [ - "{\"Software versions\": [{\"version\": \"2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\", \"module\": \"Python\"}, {\"version\": \"1.1.0\", \"module\": \"IPython\"}, {\"version\": \"posix [darwin]\", \"module\": \"OS\"}, {\"version\": \"1.8.1\", \"module\": \"numpy\"}, {\"version\": \"0.20.2\", \"module\": \"Cython\"}, {\"version\": \"0.13.3\", \"module\": \"numba\"}, {\"version\": \"0.3.0\", \"module\": \"hope\"}]}" - ], - "latex": [ - "\\begin{tabular}{|l|l|}\\hline\n", - "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", - "Python & 2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] \\\\ \\hline\n", - "IPython & 1.1.0 \\\\ \\hline\n", - "OS & posix [darwin] \\\\ \\hline\n", - "numpy & 1.8.1 \\\\ \\hline\n", - "Cython & 0.20.2 \\\\ \\hline\n", - "numba & 0.13.3 \\\\ \\hline\n", - "hope & 0.3.0 \\\\ \\hline\n", - "\\hline \\multicolumn{2}{|l|}{Thu Sep 04 15:18:18 2014 CEST} \\\\ \\hline\n", - "\\end{tabular}\n" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "Software versions\n", - "Python 2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\n", - "IPython 1.1.0\n", - "OS posix [darwin]\n", - "numpy 1.8.1\n", - "Cython 0.20.2\n", - "numba 0.13.3\n", - "hope 0.3.0\n", - "Thu Sep 04 15:18:18 2014 CEST" + "data": { + "application/json": { + "Software versions": [ + { + "module": "Python", + "version": "3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]" + }, + { + "module": "IPython", + "version": "6.1.0" + }, + { + "module": "OS", + "version": "Darwin 15.6.0 x86_64 i386 64bit" + }, + { + "module": "numpy", + "version": "1.13.1" + }, + { + "module": "Cython", + "version": "0.26" + }, + { + "module": "numba", + "version": "0.34.0" + }, + { + "module": "hope", + "version": "0.6.1" + } ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Pure python version\n", - "\n", - "def pairwise_python(X, D):\n", - " M = X.shape[0]\n", - " N = X.shape[1]\n", - " for i in range(M):\n", - " for j in range(M):\n", - " d = 0.0\n", - " for k in range(N):\n", - " tmp = X[i, k] - X[j, k]\n", - " d += tmp * tmp\n", - " D[i, j] = np.sqrt(d)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# Numpy python version\n", - "\n", - "def pairwise_numpy(X, D):\n", - " M = X.shape[0]\n", - " for i in range(M):\n", - " D[i, :] = np.sqrt(np.sum((X[i, :] - X[:]) ** 2, axis=1))" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# numba version\n", - "@numba.jit(nopython=True)\n", - "def pairwise_numba(X, D):\n", - " M = X.shape[0]\n", - " N = X.shape[1]\n", - " for i in range(M):\n", - " for j in range(M):\n", - " d = 0.0\n", - " for k in range(N):\n", - " tmp = X[i, k] - X[j, k]\n", - " d += tmp * tmp\n", - " D[i, j] = np.sqrt(d)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 4 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "\n", - "cimport cython\n", - "from libc.math cimport sqrt\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def pairwise_cython(double[:, ::1] X, double[:, ::1] D):\n", - " cdef int M = X.shape[0]\n", - " cdef int N = X.shape[1]\n", - " cdef double tmp, d\n", - " for i in range(M):\n", - " for j in range(M):\n", - " d = 0.0\n", - " for k in range(N):\n", - " tmp = X[i, k] - X[j, k]\n", - " d += tmp * tmp\n", - " D[i, j] = sqrt(d)" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 5 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "# hope version\n", - "@hope.jit\n", - "def pairwise_hope(X, D, M, N):\n", - " for i in range(M):\n", - " for j in range(M):\n", - " d = 0.0\n", - " for k in range(N):\n", - " tmp = X[i, k] - X[j, k]\n", - " d += tmp * tmp\n", - " D[i, j] = np.sqrt(d)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from native_util import load\n", - "\n", - "native_pairwise_mod = load(\"pairwise\")\n", - "pairwise_native = native_pairwise_mod.run" - ], - "language": "python", + }, + "text/html": [ + "
SoftwareVersion
Python3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
IPython6.1.0
OSDarwin 15.6.0 x86_64 i386 64bit
numpy1.13.1
Cython0.26
numba0.34.0
hope0.6.1
Mon Sep 04 15:15:37 2017 CEST
" + ], + "text/latex": [ + "\\begin{tabular}{|l|l|}\\hline\n", + "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", + "Python & 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] \\\\ \\hline\n", + "IPython & 6.1.0 \\\\ \\hline\n", + "OS & Darwin 15.6.0 x86\\_64 i386 64bit \\\\ \\hline\n", + "numpy & 1.13.1 \\\\ \\hline\n", + "Cython & 0.26 \\\\ \\hline\n", + "numba & 0.34.0 \\\\ \\hline\n", + "hope & 0.6.1 \\\\ \\hline\n", + "\\hline \\multicolumn{2}{|l|}{Mon Sep 04 15:15:37 2017 CEST} \\\\ \\hline\n", + "\\end{tabular}\n" + ], + "text/plain": [ + "Software versions\n", + "Python 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n", + "IPython 6.1.0\n", + "OS Darwin 15.6.0 x86_64 i386 64bit\n", + "numpy 1.13.1\n", + "Cython 0.26\n", + "numba 0.34.0\n", + "hope 0.6.1\n", + "Mon Sep 04 15:15:37 2017 CEST" + ] + }, + "execution_count": 2, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'pairwise' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/pairwise.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/pairwise.o -o ./pairwise.so\n", - "\n" - ] - } - ], - "prompt_number": 7 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import hope\n", + "hope.config.optimize = True\n", + "hope.config.verbose = True\n", + "hope.config.keeptemp = True\n", + "import numba\n", + "import numpy as np\n", + "from util import perf_comp_data\n", + "from native_util import load\n", + "%load_ext Cython\n", + "%load_ext version_information\n", + "%version_information numpy, Cython, numba, hope" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Pure python version\n", + "\n", + "def pairwise_python(X, D):\n", + " M = X.shape[0]\n", + " N = X.shape[1]\n", + " for i in range(M):\n", + " for j in range(M):\n", + " d = 0.0\n", + " for k in range(N):\n", + " tmp = X[i, k] - X[j, k]\n", + " d += tmp * tmp\n", + " D[i, j] = np.sqrt(d)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Numpy python version\n", + "\n", + "def pairwise_numpy(X, D):\n", + " M = X.shape[0]\n", + " for i in range(M):\n", + " D[i, :] = np.sqrt(np.sum((X[i, :] - X[:]) ** 2, axis=1))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# numba version\n", + "@numba.jit(nopython=True)\n", + "def pairwise_numba(X, D):\n", + " M = X.shape[0]\n", + " N = X.shape[1]\n", + " for i in range(M):\n", + " for j in range(M):\n", + " d = 0.0\n", + " for k in range(N):\n", + " tmp = X[i, k] - X[j, k]\n", + " d += tmp * tmp\n", + " D[i, j] = np.sqrt(d)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "%%cython\n", + "\n", + "cimport cython\n", + "from libc.math cimport sqrt\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "def pairwise_cython(double[:, ::1] X, double[:, ::1] D):\n", + " cdef size_t M = X.shape[0]\n", + " cdef size_t N = X.shape[1]\n", + " cdef double tmp, d\n", + " for i in range(M):\n", + " for j in range(M):\n", + " d = 0.0\n", + " for k in range(N):\n", + " tmp = X[i, k] - X[j, k]\n", + " d += tmp * tmp\n", + " D[i, j] = sqrt(d)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# hope version\n", + "@hope.jit\n", + "def pairwise_hope(X, D, M, N):\n", + " for i in range(M):\n", + " for j in range(M):\n", + " d = 0.0\n", + " for k in range(N):\n", + " tmp = X[i, k] - X[j, k]\n", + " d += tmp * tmp\n", + " D[i, j] = np.sqrt(d)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "X = np.random.random((1000, 3))\n", - "D = np.empty((1000, 1000))" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 8 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "running build_ext\n", + "\n" + ] + } + ], + "source": [ + "from native_util import load\n", + "\n", + "native_pairwise_mod = load(\"pairwise\")\n", + "pairwise_native = native_pairwise_mod.run" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "X = np.random.random((1000, 3))\n", + "D = np.empty((1000, 1000))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "D1 = np.empty((1000, 1000))\n", - "D2 = np.empty((1000, 1000))\n", - "D3 = np.empty((1000, 1000))\n", - "D4 = np.empty((1000, 1000))\n", - "D5 = np.empty((1000, 1000))\n", - "D6 = np.empty((1000, 1000))\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "pairwise_hope(float64^2 X, float64^2 D, int64 M, int64 N)\n", + "\tfor i.l in (0.J:M.J) {\n", + "\t\tfor j.l in (0.J:M.J) {\n", + "\t\t\tnew d.D\n", + "\t\t\td.D = 0.0.D\n", + "\t\t\tfor k.l in (0.J:N.J) {\n", + "\t\t\t\tnew tmp.d\n", + "\t\t\t\ttmp.d = (X.d[i.l, k.l] - X.d[j.l, k.l])\n", + "\t\t\t\td.D += (tmp.d * tmp.d)\n", + "\t\t\t}\n", + "\t\t\tD.d[i.l, j.l] = numpy.sqrt(d.D)\n", + "\t\t}\n", + "\t}\n", "\n", - "pairwise_python(X, D1)\n", - "pairwise_numpy(X, D2)\n", - "pairwise_numba(X, D3)\n", - "pairwise_cython(X, D4)\n", - "pairwise_hope(X, D5, X.shape[0], X.shape[1])\n", - "pairwise_native(X, D6, X.shape[0], X.shape[1])\n", + "Compiling following functions:\n", + "pairwise_hope(float64^2 X, float64^2 D, int64 M, int64 N)\n", + "running build_ext\n", + "building 'pairwise_hope_f82cb8a6ea3aecbde9f728fa85088b51f5bdf7d8ef8b740b9c0b788a_0' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch i386 -arch x86_64 -g\n", "\n", - "assert np.allclose(D1, D2)\n", - "assert np.allclose(D1, D3)\n", - "assert np.allclose(D1, D4)\n", - "assert np.allclose(D1, D5)\n", - "assert np.allclose(D1, D6)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 10 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print \"naive python\"\n", - "%timeit pairwise_python(X, D)\n", - "print \"numpy\"\n", - "%timeit pairwise_numpy(X, D)\n", - "print \"numba\"\n", - "%timeit pairwise_numba(X, D)\n", - "print \"cython\"\n", - "%timeit pairwise_cython(X, D)\n", - "print \"hope\"\n", - "%timeit pairwise_hope(X, D, X.shape[0], X.shape[1])\n", - "print \"native\"\n", - "%timeit pairwise_native(X, D, X.shape[0], X.shape[1])" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "naive python\n", - "1 loops, best of 3: 5.75 s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numpy\n", - "10 loops, best of 3: 36.6 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numba\n", - "100 loops, best of 3: 6.88 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "cython\n", - "100 loops, best of 3: 4.22 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope\n", - "100 loops, best of 3: 6.36 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "native\n", - "100 loops, best of 3: 4.23 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 11 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "from util import perf_comp_data" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hope6c1ewncq/pairwise_hope_f82cb8a6ea3aecbde9f728fa85088b51f5bdf7d8ef8b740b9c0b788a_0.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hope6c1ewncq/pairwise_hope_f82cb8a6ea3aecbde9f728fa85088b51f5bdf7d8ef8b740b9c0b788a_0.o -o /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hope6c1ewncq/pairwise_hope_f82cb8a6ea3aecbde9f728fa85088b51f5bdf7d8ef8b740b9c0b788a_0.cpython-35m-darwin.so\n", + "\n" + ] + } + ], + "source": [ + "D1 = np.empty((1000, 1000))\n", + "D2 = np.empty((1000, 1000))\n", + "D3 = np.empty((1000, 1000))\n", + "D4 = np.empty((1000, 1000))\n", + "D5 = np.empty((1000, 1000))\n", + "D6 = np.empty((1000, 1000))\n", + "\n", + "pairwise_python(X, D1)\n", + "pairwise_numpy(X, D2)\n", + "pairwise_numba(X, D3)\n", + "pairwise_cython(X, D4)\n", + "pairwise_hope(X, D5, X.shape[0], X.shape[1])\n", + "pairwise_native(X, D6, X.shape[0], X.shape[1])\n", + "\n", + "assert np.allclose(D1, D2)\n", + "assert np.allclose(D1, D3)\n", + "assert np.allclose(D1, D4)\n", + "assert np.allclose(D1, D5)\n", + "assert np.allclose(D1, D6)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "M, N = X.shape\n", - "data_list = 4*[\"X, D\"]+ 2*[\"X, D, M, N\"]\n", - "#print data_list\n", - "perf_comp_data([\"pairwise_python\", \n", - " \"pairwise_numpy\", \n", - " \"pairwise_numba\", \n", - " \"pairwise_cython\", \n", - " \"pairwise_hope\",\n", - " \"pairwise_native\"],\n", - " data_list, rep=100)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: pairwise_native , av. time sec: 0.00420749, min. time sec: 0.00414991, relative: 1.0\n", - "function: pairwise_cython , av. time sec: 0.00421405, min. time sec: 0.00415277, relative: 1.0\n", - "function: pairwise_hope , av. time sec: 0.00635457, min. time sec: 0.00626707, relative: 1.5\n", - "function: pairwise_numba , av. time sec: 0.00690150, min. time sec: 0.00681400, relative: 1.6\n", - "function: pairwise_numpy , av. time sec: 0.03677249, min. time sec: 0.03618908, relative: 8.7\n", - "function: pairwise_python , av. time sec: 5.90122139, min. time sec: 5.63599896, relative: 1402.6\n" - ] - } - ], - "prompt_number": 13 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "naive python\n", + "3.99 s ± 64.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n", + "numpy\n", + "42 ms ± 1.26 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n", + "numba\n", + "4.63 ms ± 131 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "cython\n", + "4.75 ms ± 82.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "hope\n", + "6.02 ms ± 117 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "native\n", + "4.72 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + ] + } + ], + "source": [ + "print(\"naive python\")\n", + "%timeit pairwise_python(X, D)\n", + "print(\"numpy\")\n", + "%timeit pairwise_numpy(X, D)\n", + "print(\"numba\")\n", + "%timeit pairwise_numba(X, D)\n", + "print(\"cython\")\n", + "%timeit pairwise_cython(X, D)\n", + "print(\"hope\")\n", + "%timeit pairwise_hope(X, D, X.shape[0], X.shape[1])\n", + "print(\"native\")\n", + "%timeit pairwise_native(X, D, X.shape[0], X.shape[1])" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from util import perf_comp_data" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "function: pairwise_numba , av. time sec: 0.00433872, min. time sec: 0.00417360, relative: 1.0\n", + "function: pairwise_cython , av. time sec: 0.00436183, min. time sec: 0.00415240, relative: 1.0\n", + "function: pairwise_native , av. time sec: 0.00436626, min. time sec: 0.00414733, relative: 1.0\n", + "function: pairwise_hope , av. time sec: 0.00550070, min. time sec: 0.00512893, relative: 1.3\n", + "function: pairwise_numpy , av. time sec: 0.03921036, min. time sec: 0.03764664, relative: 9.0\n", + "function: pairwise_python , av. time sec: 4.04625443, min. time sec: 3.89136448, relative: 932.6\n" + ] } ], - "metadata": {} + "source": [ + "M, N = X.shape\n", + "data_list = 4*[\"X, D\"]+ 2*[\"X, D, M, N\"]\n", + "#print data_list\n", + "perf_comp_data([\"pairwise_python\", \n", + " \"pairwise_numpy\", \n", + " \"pairwise_numba\", \n", + " \"pairwise_cython\", \n", + " \"pairwise_hope\",\n", + " \"pairwise_native\"],\n", + " data_list, rep=100)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" } - ] -} \ No newline at end of file + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/simplify.ipynb b/benchmarks/simplify.ipynb index 5da6ab1..44bf5d6 100644 --- a/benchmarks/simplify.ipynb +++ b/benchmarks/simplify.ipynb @@ -1,346 +1,898 @@ { - "metadata": { - "name": "", - "signature": "sha256:162f3d58c482919f419e58ffcac472a163f0e58c1278956fd7cefd2e91118997" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import hope\n", - "hope.config.optimize = True\n", - "hope.config.verbose = True\n", - "hope.config.keeptemp = True\n", - "import numba\n", - "import numpy as np\n", - "import numexpr as ne\n", - "\n", - "from util import perf_comp_data\n", - "from native_util import load\n", - "%load_ext cythonmagic\n", - "%load_ext version_information\n", - "%version_information numpy, Cython, numba, hope, numexpr" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "
SoftwareVersion
Python2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
IPython1.1.0
OSposix [darwin]
numpy1.8.1
Cython0.20.2
numba0.13.3
hope0.3.0
numexpr2.4
Thu Sep 04 15:17:12 2014 CEST
" - ], - "json": [ - "{\"Software versions\": [{\"version\": \"2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\", \"module\": \"Python\"}, {\"version\": \"1.1.0\", \"module\": \"IPython\"}, {\"version\": \"posix [darwin]\", \"module\": \"OS\"}, {\"version\": \"1.8.1\", \"module\": \"numpy\"}, {\"version\": \"0.20.2\", \"module\": \"Cython\"}, {\"version\": \"0.13.3\", \"module\": \"numba\"}, {\"version\": \"0.3.0\", \"module\": \"hope\"}, {\"version\": \"2.4\", \"module\": \"numexpr\"}]}" - ], - "latex": [ - "\\begin{tabular}{|l|l|}\\hline\n", - "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", - "Python & 2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] \\\\ \\hline\n", - "IPython & 1.1.0 \\\\ \\hline\n", - "OS & posix [darwin] \\\\ \\hline\n", - "numpy & 1.8.1 \\\\ \\hline\n", - "Cython & 0.20.2 \\\\ \\hline\n", - "numba & 0.13.3 \\\\ \\hline\n", - "hope & 0.3.0 \\\\ \\hline\n", - "numexpr & 2.4 \\\\ \\hline\n", - "\\hline \\multicolumn{2}{|l|}{Thu Sep 04 15:17:12 2014 CEST} \\\\ \\hline\n", - "\\end{tabular}\n" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "Software versions\n", - "Python 2.7.8 (default, Jul 13 2014, 17:11:32) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\n", - "IPython 1.1.0\n", - "OS posix [darwin]\n", - "numpy 1.8.1\n", - "Cython 0.20.2\n", - "numba 0.13.3\n", - "hope 0.3.0\n", - "numexpr 2.4\n", - "Thu Sep 04 15:17:12 2014 CEST" + "data": { + "application/json": { + "Software versions": [ + { + "module": "Python", + "version": "3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]" + }, + { + "module": "IPython", + "version": "6.1.0" + }, + { + "module": "OS", + "version": "Darwin 15.6.0 x86_64 i386 64bit" + }, + { + "module": "numpy", + "version": "1.13.1" + }, + { + "module": "Cython", + "version": "0.26" + }, + { + "module": "numba", + "version": "0.34.0" + }, + { + "module": "hope", + "version": "0.6.1" + }, + { + "module": "numexpr", + "version": "2.6.2" + } ] - } - ], - "prompt_number": 1 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def poly(res, arg):\n", - " res[:] = np.sin(arg)**2 + (arg**3 + arg**2 - arg - 1)/(arg**2 + 2*arg + 1) + np.cos(arg)**2\n", - "hope_poly = hope.jit(poly)\n", - "numba_poly = numba.jit(poly, nopython=False)\n", - "\n", - "native_poly_mod = load(\"poly\")\n", - "native_poly = native_poly_mod.run\n" - ], - "language": "python", + }, + "text/html": [ + "
SoftwareVersion
Python3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
IPython6.1.0
OSDarwin 15.6.0 x86_64 i386 64bit
numpy1.13.1
Cython0.26
numba0.34.0
hope0.6.1
numexpr2.6.2
Mon Sep 04 15:28:09 2017 CEST
" + ], + "text/latex": [ + "\\begin{tabular}{|l|l|}\\hline\n", + "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", + "Python & 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] \\\\ \\hline\n", + "IPython & 6.1.0 \\\\ \\hline\n", + "OS & Darwin 15.6.0 x86\\_64 i386 64bit \\\\ \\hline\n", + "numpy & 1.13.1 \\\\ \\hline\n", + "Cython & 0.26 \\\\ \\hline\n", + "numba & 0.34.0 \\\\ \\hline\n", + "hope & 0.6.1 \\\\ \\hline\n", + "numexpr & 2.6.2 \\\\ \\hline\n", + "\\hline \\multicolumn{2}{|l|}{Mon Sep 04 15:28:09 2017 CEST} \\\\ \\hline\n", + "\\end{tabular}\n" + ], + "text/plain": [ + "Software versions\n", + "Python 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n", + "IPython 6.1.0\n", + "OS Darwin 15.6.0 x86_64 i386 64bit\n", + "numpy 1.13.1\n", + "Cython 0.26\n", + "numba 0.34.0\n", + "hope 0.6.1\n", + "numexpr 2.6.2\n", + "Mon Sep 04 15:28:09 2017 CEST" + ] + }, + "execution_count": 1, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'poly' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/Library/Python/2.7/lib/python/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/poly.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db46 ./src/poly.o -o ./poly.so\n", - "\n" - ] - } - ], - "prompt_number": 2 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import hope\n", + "hope.config.optimize = True\n", + "hope.config.verbose = True\n", + "hope.config.keeptemp = True\n", + "import numba\n", + "import numpy as np\n", + "import numexpr as ne\n", + "\n", + "from util import perf_comp_data\n", + "from native_util import load\n", + "%load_ext Cython\n", + "%load_ext version_information\n", + "%version_information numpy, Cython, numba, hope, numexpr" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "running build_ext\n", + "building 'poly' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "cimport cython\n", - "from libc.math cimport sin\n", - "from libc.math cimport cos\n", - "from libc.math cimport pow\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def cython_poly(double[:] res, double[:] arg):\n", - " for i in range(len(arg)):\n", - " i_arg = arg[i]\n", - " res[i] = pow(sin(i_arg),2) + (pow(i_arg,3) + pow(i_arg,2) - i_arg - 1)/(pow(i_arg,2) + 2*i_arg + 1) + pow(cos(i_arg),2)\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: ././src/poly.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g ./src/poly.o -o ./poly.cpython-35m-darwin.so\n", "\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, + ] + } + ], + "source": [ + "def poly(res, arg):\n", + " res[:] = np.sin(arg)**2 + (arg**3 + arg**2 - arg - 1)/(arg**2 + 2*arg + 1) + np.cos(arg)**2\n", + "hope_poly = hope.jit(poly)\n", + "numba_poly = numba.jit(poly, nopython=False)\n", + "\n", + "native_poly_mod = load(\"poly\")\n", + "native_poly = native_poly_mod.run\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "cimport cython\n", - "import numpy as np\n", - "cimport numpy as np\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "building '_cython_magic_c56f3cd16e138e603a8a648f0cd9159f' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def cython_numpy_poly(np.ndarray[np.double_t, ndim=1] res, np.ndarray[np.double_t, ndim=1] arg):\n", - " res[:] = np.sin(arg)**2 + (arg**3 + arg**2 - arg - 1)/(arg**2 + 2*arg + 1) + np.cos(arg)**2\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 4 + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "clang: /Users/uweschmitt/.ipython/cython/_cython_magic_c56f3cd16e138e603a8a648f0cd9159f.c\n", + "/usr/bin/clang -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /Users/uweschmitt/.ipython/cython/Users/uweschmitt/.ipython/cython/_cython_magic_c56f3cd16e138e603a8a648f0cd9159f.o -o /Users/uweschmitt/.ipython/cython/_cython_magic_c56f3cd16e138e603a8a648f0cd9159f.cpython-35m-darwin.so\n" + ] }, { - "cell_type": "code", - "collapsed": false, - "input": [ - "# NumExpr version\n", - "\n", - "import numexpr as ne\n", - "\n", - "def numexpr_poly(res, arg):\n", - " res[:] = ne.evaluate(\"sin(arg)**2 + (arg**3 + arg**2 - arg - 1)/(arg**2 + 2*arg + 1) + cos(arg)**2\")\n" - ], - "language": "python", + "data": { + "text/html": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " Cython: _cython_magic_c56f3cd16e138e603a8a648f0cd9159f.pyx\n", + " \n", + " \n", + "\n", + "\n", + "

Generated by Cython 0.26

\n", + "

\n", + " Yellow lines hint at Python interaction.
\n", + " Click on a line that starts with a \"+\" to see the C code that Cython generated for it.\n", + "

\n", + "
 01: 
\n", + "
+02: cimport cython
\n", + "
  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 2, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "
 03: from libc.math cimport sin
\n", + "
 04: from libc.math cimport cos
\n", + "
 05: from libc.math cimport pow
\n", + "
 06: 
\n", + "
 07: @cython.boundscheck(False)
\n", + "
 08: @cython.wraparound(False)
\n", + "
 09: @cython.cdivision(True)
\n", + "
+10: def cython_poly(double[:] res, double[:] arg):
\n", + "
/* Python wrapper */\n",
+       "static PyObject *__pyx_pw_46_cython_magic_c56f3cd16e138e603a8a648f0cd9159f_1cython_poly(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/\n",
+       "static PyMethodDef __pyx_mdef_46_cython_magic_c56f3cd16e138e603a8a648f0cd9159f_1cython_poly = {\"cython_poly\", (PyCFunction)__pyx_pw_46_cython_magic_c56f3cd16e138e603a8a648f0cd9159f_1cython_poly, METH_VARARGS|METH_KEYWORDS, 0};\n",
+       "static PyObject *__pyx_pw_46_cython_magic_c56f3cd16e138e603a8a648f0cd9159f_1cython_poly(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {\n",
+       "  __Pyx_memviewslice __pyx_v_res = { 0, 0, { 0 }, { 0 }, { 0 } };\n",
+       "  __Pyx_memviewslice __pyx_v_arg = { 0, 0, { 0 }, { 0 }, { 0 } };\n",
+       "  PyObject *__pyx_r = 0;\n",
+       "  __Pyx_RefNannyDeclarations\n",
+       "  __Pyx_RefNannySetupContext(\"cython_poly (wrapper)\", 0);\n",
+       "  {\n",
+       "    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_res,&__pyx_n_s_arg,0};\n",
+       "    PyObject* values[2] = {0,0};\n",
+       "    if (unlikely(__pyx_kwds)) {\n",
+       "      Py_ssize_t kw_args;\n",
+       "      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);\n",
+       "      switch (pos_args) {\n",
+       "        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);\n",
+       "        CYTHON_FALLTHROUGH;\n",
+       "        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);\n",
+       "        CYTHON_FALLTHROUGH;\n",
+       "        case  0: break;\n",
+       "        default: goto __pyx_L5_argtuple_error;\n",
+       "      }\n",
+       "      kw_args = PyDict_Size(__pyx_kwds);\n",
+       "      switch (pos_args) {\n",
+       "        case  0:\n",
+       "        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_res)) != 0)) kw_args--;\n",
+       "        else goto __pyx_L5_argtuple_error;\n",
+       "        CYTHON_FALLTHROUGH;\n",
+       "        case  1:\n",
+       "        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_arg)) != 0)) kw_args--;\n",
+       "        else {\n",
+       "          __Pyx_RaiseArgtupleInvalid(\"cython_poly\", 1, 2, 2, 1); __PYX_ERR(0, 10, __pyx_L3_error)\n",
+       "        }\n",
+       "      }\n",
+       "      if (unlikely(kw_args > 0)) {\n",
+       "        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, \"cython_poly\") < 0)) __PYX_ERR(0, 10, __pyx_L3_error)\n",
+       "      }\n",
+       "    } else if (PyTuple_GET_SIZE(__pyx_args) != 2) {\n",
+       "      goto __pyx_L5_argtuple_error;\n",
+       "    } else {\n",
+       "      values[0] = PyTuple_GET_ITEM(__pyx_args, 0);\n",
+       "      values[1] = PyTuple_GET_ITEM(__pyx_args, 1);\n",
+       "    }\n",
+       "    __pyx_v_res = __Pyx_PyObject_to_MemoryviewSlice_ds_double(values[0]); if (unlikely(!__pyx_v_res.memview)) __PYX_ERR(0, 10, __pyx_L3_error)\n",
+       "    __pyx_v_arg = __Pyx_PyObject_to_MemoryviewSlice_ds_double(values[1]); if (unlikely(!__pyx_v_arg.memview)) __PYX_ERR(0, 10, __pyx_L3_error)\n",
+       "  }\n",
+       "  goto __pyx_L4_argument_unpacking_done;\n",
+       "  __pyx_L5_argtuple_error:;\n",
+       "  __Pyx_RaiseArgtupleInvalid(\"cython_poly\", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 10, __pyx_L3_error)\n",
+       "  __pyx_L3_error:;\n",
+       "  __Pyx_AddTraceback(\"_cython_magic_c56f3cd16e138e603a8a648f0cd9159f.cython_poly\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return NULL;\n",
+       "  __pyx_L4_argument_unpacking_done:;\n",
+       "  __pyx_r = __pyx_pf_46_cython_magic_c56f3cd16e138e603a8a648f0cd9159f_cython_poly(__pyx_self, __pyx_v_res, __pyx_v_arg);\n",
+       "\n",
+       "  /* function exit code */\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return __pyx_r;\n",
+       "}\n",
+       "\n",
+       "static PyObject *__pyx_pf_46_cython_magic_c56f3cd16e138e603a8a648f0cd9159f_cython_poly(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_res, __Pyx_memviewslice __pyx_v_arg) {\n",
+       "  int __pyx_v_i;\n",
+       "  double __pyx_v_i_arg;\n",
+       "  PyObject *__pyx_r = NULL;\n",
+       "  __Pyx_RefNannyDeclarations\n",
+       "  __Pyx_RefNannySetupContext(\"cython_poly\", 0);\n",
+       "/* … */\n",
+       "  /* function exit code */\n",
+       "  __pyx_r = Py_None; __Pyx_INCREF(Py_None);\n",
+       "  goto __pyx_L0;\n",
+       "  __pyx_L1_error:;\n",
+       "  __Pyx_XDECREF(__pyx_t_1);\n",
+       "  __Pyx_AddTraceback(\"_cython_magic_c56f3cd16e138e603a8a648f0cd9159f.cython_poly\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
+       "  __pyx_r = NULL;\n",
+       "  __pyx_L0:;\n",
+       "  __PYX_XDEC_MEMVIEW(&__pyx_v_res, 1);\n",
+       "  __PYX_XDEC_MEMVIEW(&__pyx_v_arg, 1);\n",
+       "  __Pyx_XGIVEREF(__pyx_r);\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return __pyx_r;\n",
+       "}\n",
+       "/* … */\n",
+       "  __pyx_tuple__20 = PyTuple_Pack(4, __pyx_n_s_res, __pyx_n_s_arg, __pyx_n_s_i, __pyx_n_s_i_arg); if (unlikely(!__pyx_tuple__20)) __PYX_ERR(0, 10, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_tuple__20);\n",
+       "  __Pyx_GIVEREF(__pyx_tuple__20);\n",
+       "/* … */\n",
+       "  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_c56f3cd16e138e603a8a648f0cd9159f_1cython_poly, NULL, __pyx_n_s_cython_magic_c56f3cd16e138e603a); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 10, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_cython_poly, __pyx_t_1) < 0) __PYX_ERR(0, 10, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  __pyx_codeobj__21 = (PyObject*)__Pyx_PyCode_New(2, 0, 4, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__20, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_uweschmitt_ipython_cython, __pyx_n_s_cython_poly, 10, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__21)) __PYX_ERR(0, 10, __pyx_L1_error)\n",
+       "
 11:     cdef int i
\n", + "
 12:     cdef double i_arg
\n", + "
+13:     for i in range(len(arg)):
\n", + "
  __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_arg, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 13, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_t_2 = PyObject_Length(__pyx_t_1); if (unlikely(__pyx_t_2 == -1)) __PYX_ERR(0, 13, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "  for (__pyx_t_3 = 0; __pyx_t_3 < __pyx_t_2; __pyx_t_3+=1) {\n",
+       "    __pyx_v_i = __pyx_t_3;\n",
+       "
+14:         i_arg = arg[i]
\n", + "
    __pyx_t_4 = __pyx_v_i;\n",
+       "    __pyx_v_i_arg = (*((double *) ( /* dim=0 */ (__pyx_v_arg.data + __pyx_t_4 * __pyx_v_arg.strides[0]) )));\n",
+       "
+15:         res[i] = pow(sin(i_arg),2) + (pow(i_arg,3) + pow(i_arg,2) - i_arg - 1)/(pow(i_arg,2) + 2*i_arg + 1) + pow(cos(i_arg),2)
\n", + "
    __pyx_t_5 = __pyx_v_i;\n",
+       "    *((double *) ( /* dim=0 */ (__pyx_v_res.data + __pyx_t_5 * __pyx_v_res.strides[0]) )) = ((pow(sin(__pyx_v_i_arg), 2.0) + ((((pow(__pyx_v_i_arg, 3.0) + pow(__pyx_v_i_arg, 2.0)) - __pyx_v_i_arg) - 1.0) / ((pow(__pyx_v_i_arg, 2.0) + (2.0 * __pyx_v_i_arg)) + 1.0))) + pow(cos(__pyx_v_i_arg), 2.0));\n",
+       "  }\n",
+       "
" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 9, "metadata": {}, - "outputs": [], - "prompt_number": 5 - }, + "output_type": "execute_result" + } + ], + "source": [ + "%%cython -a\n", + "\n", + "cimport cython\n", + "from libc.math cimport sin\n", + "from libc.math cimport cos\n", + "from libc.math cimport pow\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "@cython.cdivision(True)\n", + "def cython_poly(double[:] res, double[:] arg):\n", + " cdef int i\n", + " cdef double i_arg\n", + " for i in range(len(arg)):\n", + " i_arg = arg[i]\n", + " res[i] = pow(sin(i_arg),2) + (pow(i_arg,3) + pow(i_arg,2) - i_arg - 1)/(pow(i_arg,2) + 2*i_arg + 1) + pow(cos(i_arg),2)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "arg = np.random.random(50000)\n", - "res = np.empty_like(arg)\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "building '_cython_magic_2c4125c086131196c2c8dcbbb7f86ef5' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "res1 = np.empty_like(arg)\n", - "res2 = np.empty_like(arg)\n", - "res3 = np.empty_like(arg)\n", - "res4 = np.empty_like(arg)\n", - "res5 = np.empty_like(arg)\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "clang: /Users/uweschmitt/.ipython/cython/_cython_magic_2c4125c086131196c2c8dcbbb7f86ef5.c\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_2c4125c086131196c2c8dcbbb7f86ef5.c:495:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_2c4125c086131196c2c8dcbbb7f86ef5.c:495:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "/usr/bin/clang -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /Users/uweschmitt/.ipython/cython/Users/uweschmitt/.ipython/cython/_cython_magic_2c4125c086131196c2c8dcbbb7f86ef5.o -o /Users/uweschmitt/.ipython/cython/_cython_magic_2c4125c086131196c2c8dcbbb7f86ef5.cpython-35m-darwin.so\n" + ] + } + ], + "source": [ + "%%cython\n", + "cimport cython\n", + "import numpy as np\n", + "cimport numpy as np\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "def cython_numpy_poly(np.ndarray[np.double_t, ndim=1] res, np.ndarray[np.double_t, ndim=1] arg):\n", + " res[:] = np.sin(arg)**2 + (arg**3 + arg**2 - arg - 1)/(arg**2 + 2*arg + 1) + np.cos(arg)**2\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# NumExpr version\n", + "\n", + "import numexpr as ne\n", + "\n", + "def numexpr_poly(res, arg):\n", + " res[:] = ne.evaluate(\"sin(arg)**2 + (arg**3 + arg**2 - arg - 1)/(arg**2 + 2*arg + 1) + cos(arg)**2\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "poly(float64^1 res, float64^1 arg)\n", + "\t(:res@0) {\n", + "\t\tres.d[:res@0] = (((numpy.sin(arg.d[:arg@0]) ** 2.J) + (((((arg.d[:arg@0] ** 3.J) + (arg.d[:arg@0] ** 2.J)) - arg.d[:arg@0]) - 1.J) / (((arg.d[:arg@0] ** 2.J) + (2.J * arg.d[:arg@0])) + 1.J))) + (numpy.cos(arg.d[:arg@0]) ** 2.J))\n", + "\t}\n", "\n", - "poly(res1, arg)\n", - "hope_poly(res2, arg)\n", - "numba_poly(res3, arg)\n", - "native_poly(res4, arg)\n", - "numexpr_poly(res5, arg)\n", + "Compiling following functions:\n", + "poly(float64^1 res, float64^1 arg)\n", + "running build_ext\n", + "building 'poly_332b2c0332e8513cfd35081ce10b11e6c57ab0ccac824978e78990c6_0' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch i386 -arch x86_64 -g\n", "\n", - "assert np.allclose(res1, res2)\n", - "assert np.allclose(res1, res3)\n", - "assert np.allclose(res1, res4)\n", - "assert np.allclose(res1, res5)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 7 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print \"python\"\n", - "%timeit poly(res, arg)\n", - "print \"hope\"\n", - "%timeit hope_poly(res, arg)\n", - "print \"numba\"\n", - "%timeit numba_poly(res, arg)\n", - "print \"cython\"\n", - "%timeit cython_poly(res, arg)\n", - "print \"cython numpy\"\n", - "%timeit cython_numpy_poly(res, arg)\n", - "print \"native\"\n", - "%timeit native_poly(res, arg)\n", - "print \"numexpr (1)\"\n", - "ne.set_num_threads(1)\n", - "%timeit numexpr_poly(res, arg)\n", - "print \"numexpr ({0})\".format(ne.detect_number_of_cores())\n", - "ne.set_num_threads(ne.detect_number_of_cores())\n", - "%timeit numexpr_poly(res, arg)\n", + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hopes3ez223s/poly_332b2c0332e8513cfd35081ce10b11e6c57ab0ccac824978e78990c6_0.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hopes3ez223s/poly_332b2c0332e8513cfd35081ce10b11e6c57ab0ccac824978e78990c6_0.o -o /var/folders/k8/zfp7dvcs1m326gz1brql1tv80000gn/T/hopes3ez223s/poly_332b2c0332e8513cfd35081ce10b11e6c57ab0ccac824978e78990c6_0.cpython-35m-darwin.so\n", "\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "python\n", - "100 loops, best of 3: 2.57 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope\n", - "10000 loops, best of 3: 29 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numba\n", - "100 loops, best of 3: 2.66 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "cython\n", - "100 loops, best of 3: 9.97 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "cython numpy\n", - "100 loops, best of 3: 2.56 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "native\n", - "100 loops, best of 3: 2.06 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numexpr (1)\n", - "1000 loops, best of 3: 1.33 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "numexpr (8)\n", - "1000 loops, best of 3: 550 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 8 - }, + ] + } + ], + "source": [ + "arg = np.random.random(50000)\n", + "res = np.empty_like(arg)\n", + "\n", + "res1 = np.empty_like(arg)\n", + "res2 = np.empty_like(arg)\n", + "res3 = np.empty_like(arg)\n", + "res4 = np.empty_like(arg)\n", + "res5 = np.empty_like(arg)\n", + "\n", + "poly(res1, arg)\n", + "hope_poly(res2, arg)\n", + "numba_poly(res3, arg)\n", + "native_poly(res4, arg)\n", + "numexpr_poly(res5, arg)\n", + "\n", + "assert np.allclose(res1, res2)\n", + "assert np.allclose(res1, res3)\n", + "assert np.allclose(res1, res4)\n", + "assert np.allclose(res1, res5)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "ne.set_num_threads(8)\n", - "perf_comp_data([\"poly\", \n", - " \"hope_poly\", \n", - " \"numba_poly\", \n", - " \"cython_poly\", \n", - " \"cython_numpy_poly\", \n", - " \"native_poly\",\n", - " \"numexpr_poly\"], \n", - " 7*[\"res, arg\"], rep=100)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: hope_poly , av. time sec: 0.00002789, min. time sec: 0.00002694, relative: 1.0\n", - "function: numexpr_poly , av. time sec: 0.00054300, min. time sec: 0.00048995, relative: 19.5\n", - "function: native_poly , av. time sec: 0.00204802, min. time sec: 0.00201893, relative: 73.4\n", - "function: cython_numpy_poly , av. time sec: 0.00257111, min. time sec: 0.00251794, relative: 92.2\n", - "function: poly , av. time sec: 0.00260139, min. time sec: 0.00251603, relative: 93.3\n", - "function: numba_poly , av. time sec: 0.00272107, min. time sec: 0.00263000, relative: 97.5\n", - "function: cython_poly , av. time sec: 0.00962663, min. time sec: 0.00949407, relative: 345.1\n" - ] - } - ], - "prompt_number": 9 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "python\n", + "2.73 ms ± 125 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "hope\n", + "28.6 µs ± 686 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "numba\n", + "697 µs ± 15.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "cython\n", + "2.23 ms ± 54.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "cython numpy\n", + "3.01 ms ± 60.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "native\n", + "2.02 ms ± 20.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "numexpr (1)\n", + "1.56 ms ± 15.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n", + "numexpr (8)\n", + "435 µs ± 28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" + ] + } + ], + "source": [ + "print(\"python\")\n", + "%timeit poly(res, arg)\n", + "print(\"hope\")\n", + "%timeit hope_poly(res, arg)\n", + "print(\"numba\")\n", + "%timeit numba_poly(res, arg)\n", + "print(\"cython\")\n", + "%timeit cython_poly(res, arg)\n", + "print(\"cython numpy\")\n", + "%timeit cython_numpy_poly(res, arg)\n", + "print(\"native\")\n", + "%timeit native_poly(res, arg)\n", + "print(\"numexpr (1)\")\n", + "ne.set_num_threads(1)\n", + "%timeit numexpr_poly(res, arg)\n", + "print(\"numexpr ({0})\".format(ne.detect_number_of_cores()))\n", + "ne.set_num_threads(ne.detect_number_of_cores())\n", + "%timeit numexpr_poly(res, arg)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "function: hope_poly , av. time sec: 0.00005208, min. time sec: 0.00002532, relative: 1.0\n", + "function: numexpr_poly , av. time sec: 0.00045749, min. time sec: 0.00039542, relative: 8.8\n", + "function: numba_poly , av. time sec: 0.00063641, min. time sec: 0.00063479, relative: 12.2\n", + "function: cython_poly , av. time sec: 0.00190999, min. time sec: 0.00176367, relative: 36.7\n", + "function: native_poly , av. time sec: 0.00193384, min. time sec: 0.00189017, relative: 37.1\n", + "function: poly , av. time sec: 0.00260737, min. time sec: 0.00242636, relative: 50.1\n", + "function: cython_numpy_poly , av. time sec: 0.00261038, min. time sec: 0.00245425, relative: 50.1\n" + ] } ], - "metadata": {} + "source": [ + "ne.set_num_threads(8)\n", + "perf_comp_data([\"poly\", \n", + " \"hope_poly\", \n", + " \"numba_poly\", \n", + " \"cython_poly\", \n", + " \"cython_numpy_poly\", \n", + " \"native_poly\",\n", + " \"numexpr_poly\"], \n", + " 7*[\"res, arg\"], rep=100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" } - ] -} \ No newline at end of file + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/benchmarks/star.ipynb b/benchmarks/star.ipynb index 09cf1f5..7fee6ab 100644 --- a/benchmarks/star.ipynb +++ b/benchmarks/star.ipynb @@ -1,494 +1,539 @@ { - "metadata": { - "name": "", - "signature": "sha256:420bd7e5c9a28bef62dee51f5a5a1770f5cec1ee324c4204a83a2dc17c7c78f0" - }, - "nbformat": 3, - "nbformat_minor": 0, - "worksheets": [ + "cells": [ { - "cells": [ + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "import hope\n", - "hope.config.optimize = True\n", - "hope.config.verbose = True\n", - "hope.config.keeptemp = True\n", - "import numba\n", - "import numpy as np\n", - "from util import perf_comp_data\n", - "from native_util import load\n", - "%load_ext cythonmagic\n", - "%load_ext version_information\n", - "%version_information numpy, Cython, numba, hope" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "html": [ - "
SoftwareVersion
Python2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]
IPython1.1.0
OSDarwin 13.4.0 x86_64 i386 64bit
numpy1.8.1
Cython0.20.2
numbatag: 0.13.3
hope0.3.0
Tue Nov 25 14:36:16 2014 CET
" - ], - "json": [ - "{\"Software versions\": [{\"version\": \"2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\", \"module\": \"Python\"}, {\"version\": \"1.1.0\", \"module\": \"IPython\"}, {\"version\": \"Darwin 13.4.0 x86_64 i386 64bit\", \"module\": \"OS\"}, {\"version\": \"1.8.1\", \"module\": \"numpy\"}, {\"version\": \"0.20.2\", \"module\": \"Cython\"}, {\"version\": \"tag: 0.13.3\", \"module\": \"numba\"}, {\"version\": \"0.3.0\", \"module\": \"hope\"}]}" - ], - "latex": [ - "\\begin{tabular}{|l|l|}\\hline\n", - "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", - "Python & 2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] \\\\ \\hline\n", - "IPython & 1.1.0 \\\\ \\hline\n", - "OS & Darwin 13.4.0 x86\\_64 i386 64bit \\\\ \\hline\n", - "numpy & 1.8.1 \\\\ \\hline\n", - "Cython & 0.20.2 \\\\ \\hline\n", - "numba & tag: 0.13.3 \\\\ \\hline\n", - "hope & 0.3.0 \\\\ \\hline\n", - "\\hline \\multicolumn{2}{|l|}{Tue Nov 25 14:36:16 2014 CET} \\\\ \\hline\n", - "\\end{tabular}\n" - ], - "metadata": {}, - "output_type": "pyout", - "prompt_number": 1, - "text": [ - "Software versions\n", - "Python 2.7.8 64bit [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]\n", - "IPython 1.1.0\n", - "OS Darwin 13.4.0 x86_64 i386 64bit\n", - "numpy 1.8.1\n", - "Cython 0.20.2\n", - "numba tag: 0.13.3\n", - "hope 0.3.0\n", - "Tue Nov 25 14:36:16 2014 CET" - ] - } - ], - "prompt_number": 1 + "name": "stdout", + "output_type": "stream", + "text": [ + "The Cython extension is already loaded. To reload it, use:\n", + " %reload_ext Cython\n", + "The version_information extension is already loaded. To reload it, use:\n", + " %reload_ext version_information\n" + ] }, { - "cell_type": "code", - "collapsed": false, - "input": [ - "b = 3.5\n", - "a = 1. / np.sqrt(2. ** (1. / (b - 1.)) - 1.)\n", - "\n", - "r50 = 2\n", - "\n", - "center = np.array([10.141, 10.414])\n", - "dims = np.array([20, 20])\n", - "# coefficients generated by http://keisan.casio.com/has10/SpecExec.cgi?id=system/2006/1280624821, 7th order\n", - "x1D = np.array([ \\\n", - " 0.5 - 0.9491079123427585245262 / 2 \\\n", - " , 0.5 - 0.7415311855993944398639 / 2 \\\n", - " , 0.5 - 0.4058451513773971669066 / 2 \\\n", - " , 0.5 \\\n", - " , 0.5 + 0.4058451513773971669066 / 2 \\\n", - " , 0.5 + 0.7415311855993944398639 / 2 \\\n", - " , 0.5 + 0.9491079123427585245262 / 2 \\\n", - "], dtype=np.float32)\n", - "w1D = np.array([ \\\n", - " 0.1294849661688696932706 / 2 \\\n", - " , 0.2797053914892766679015 / 2 \\\n", - " , 0.38183005050511894495 / 2 \\\n", - " , 0.4179591836734693877551 / 2 \\\n", - " , 0.38183005050511894495 / 2 \\\n", - " , 0.2797053914892766679015 / 2 \\\n", - " , 0.1294849661688696932706 / 2 \\\n", - "], dtype=np.float32)\n", - "w2D = np.outer(w1D, w1D)\n", - "\n", - "print dims.dtype" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "int64\n" + "data": { + "application/json": { + "Software versions": [ + { + "module": "Python", + "version": "3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]" + }, + { + "module": "IPython", + "version": "6.1.0" + }, + { + "module": "OS", + "version": "Darwin 15.6.0 x86_64 i386 64bit" + }, + { + "module": "numpy", + "version": "1.13.1" + }, + { + "module": "Cython", + "version": "0.26" + }, + { + "module": "numba", + "version": "0.34.0" + }, + { + "module": "hope", + "version": "0.6.1" + } ] - } - ], - "prompt_number": 2 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "def pdf(density, dims, center, w2D, r50, b, a):\n", - " for x in range(dims[0]):\n", - " for y in range(dims[1]):\n", - " dr = np.sqrt((x - center[0]) ** 2 + (y - center[1]) ** 2)\n", - " density[x, y] = np.sum(w2D * 2 * (b - 1) / (2 * np.pi * (r50 * a)**2) * (1 + (dr / (r50 * a))**2)**(-b))\n", - " return density" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 3 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "#Naive Cython implementation\n", - "cimport cython\n", - "import numpy as np\n", - "cimport numpy as np\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def cython_pdf(np.ndarray[np.float32_t, ndim=2] density, \n", - " np.ndarray[np.long_t, ndim=1] dims, \n", - " np.ndarray[np.float_t, ndim=1] center, \n", - " np.ndarray[np.float32_t, ndim=2] w2D, \n", - " float r50, \n", - " float b, \n", - " float a):\n", - " \n", - " cdef double dr = 0.0\n", - "\n", - " for x in range(dims[0]):\n", - " for y in range(dims[1]):\n", - " dr = np.sqrt((x - center[0]) ** 2 + (y - center[1]) ** 2)\n", - " density[x, y] = np.sum(w2D * 2 * (b - 1) / (2 * np.pi * (r50 * a)**2) * (1 + (dr / (r50 * a))**2)**(-b))\n", - " return density\n", - "\n", - "\n" - ], - "language": "python", + }, + "text/html": [ + "
SoftwareVersion
Python3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
IPython6.1.0
OSDarwin 15.6.0 x86_64 i386 64bit
numpy1.13.1
Cython0.26
numba0.34.0
hope0.6.1
Mon Sep 04 16:22:08 2017 CEST
" + ], + "text/latex": [ + "\\begin{tabular}{|l|l|}\\hline\n", + "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n", + "Python & 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] \\\\ \\hline\n", + "IPython & 6.1.0 \\\\ \\hline\n", + "OS & Darwin 15.6.0 x86\\_64 i386 64bit \\\\ \\hline\n", + "numpy & 1.13.1 \\\\ \\hline\n", + "Cython & 0.26 \\\\ \\hline\n", + "numba & 0.34.0 \\\\ \\hline\n", + "hope & 0.6.1 \\\\ \\hline\n", + "\\hline \\multicolumn{2}{|l|}{Mon Sep 04 16:22:08 2017 CEST} \\\\ \\hline\n", + "\\end{tabular}\n" + ], + "text/plain": [ + "Software versions\n", + "Python 3.5.1 64bit [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]\n", + "IPython 6.1.0\n", + "OS Darwin 15.6.0 x86_64 i386 64bit\n", + "numpy 1.13.1\n", + "Cython 0.26\n", + "numba 0.34.0\n", + "hope 0.6.1\n", + "Mon Sep 04 16:22:08 2017 CEST" + ] + }, + "execution_count": 47, "metadata": {}, - "outputs": [], - "prompt_number": 4 - }, + "output_type": "execute_result" + } + ], + "source": [ + "import hope\n", + "hope.config.optimize = True\n", + "hope.config.verbose = True\n", + "hope.config.keeptemp = True\n", + "import numba\n", + "import numpy as np\n", + "from util import perf_comp_data\n", + "from native_util import load\n", + "%load_ext Cython\n", + "%load_ext version_information\n", + "%version_information numpy, Cython, numba, hope" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "#Modestly tunned Cython implementation\n", - "cimport cython\n", - "import numpy as np\n", - "cimport numpy as np\n", - "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "def cython_pdf_opt(np.ndarray[np.float32_t, ndim=2] density, \n", - " np.ndarray[np.int64_t, ndim=1] dims, \n", - " np.ndarray[np.float64_t, ndim=1] center, \n", - " np.ndarray[np.float32_t, ndim=2] w2D, \n", - " float r50, \n", - " float b, \n", - " np.float32_t a):\n", - " \n", - " cdef np.float32_t pi = np.pi\n", - " cdef np.float32_t dr = 0.0\n", - " cdef int x, y\n", - " \n", - " for x in range(dims[0]):\n", - " for y in range(dims[1]):\n", - " dr = ((x - center[0]) ** 2 + (y - center[1]) ** 2)**(0.5)\n", - " density[x, y] = np.sum(2. * (b - 1.) / (2. * pi * (r50 * a)**2) * (1. + (dr / (r50 * a))**2)**(-b) * w2D)\n", - " return density" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 5 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "int64\n" + ] + } + ], + "source": [ + "b = 3.5\n", + "a = 1. / np.sqrt(2. ** (1. / (b - 1.)) - 1.)\n", + "\n", + "r50 = 2\n", + "\n", + "center = np.array([10.141, 10.414])\n", + "dims = np.array([20, 20])\n", + "# coefficients generated by http://keisan.casio.com/has10/SpecExec.cgi?id=system/2006/1280624821, 7th order\n", + "x1D = np.array([ \\\n", + " 0.5 - 0.9491079123427585245262 / 2 \\\n", + " , 0.5 - 0.7415311855993944398639 / 2 \\\n", + " , 0.5 - 0.4058451513773971669066 / 2 \\\n", + " , 0.5 \\\n", + " , 0.5 + 0.4058451513773971669066 / 2 \\\n", + " , 0.5 + 0.7415311855993944398639 / 2 \\\n", + " , 0.5 + 0.9491079123427585245262 / 2 \\\n", + "], dtype=np.float32)\n", + "w1D = np.array([ \\\n", + " 0.1294849661688696932706 / 2 \\\n", + " , 0.2797053914892766679015 / 2 \\\n", + " , 0.38183005050511894495 / 2 \\\n", + " , 0.4179591836734693877551 / 2 \\\n", + " , 0.38183005050511894495 / 2 \\\n", + " , 0.2797053914892766679015 / 2 \\\n", + " , 0.1294849661688696932706 / 2 \\\n", + "], dtype=np.float32)\n", + "w2D = np.outer(w1D, w1D)\n", + "\n", + "print(dims.dtype)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def pdf(density, dims, center, w2D, r50, b, a):\n", + " for x in range(dims[0]):\n", + " for y in range(dims[1]):\n", + " dr = np.sqrt((x - center[0]) ** 2 + (y - center[1]) ** 2)\n", + " density[x, y] = np.sum(w2D * 2 * (b - 1) / (2 * np.pi * (r50 * a)**2) * (1 + (dr / (r50 * a))**2)**(-b))\n", + " return density" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "%%cython\n", - "#Aggresively tunned Cython implementation\n", - "cimport cython\n", - "import numpy as np\n", - "cimport numpy as np\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "building '_cython_magic_f24e61fd7e336481e3f458d73845fd48' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch i386 -arch x86_64 -g\n", "\n", - "@cython.boundscheck(False)\n", - "@cython.wraparound(False)\n", - "@cython.cdivision(True)\n", - "def cython_pdf_unrolled(np.ndarray[np.float32_t, ndim=2] density, \n", - " np.ndarray[np.long_t, ndim=1] dims, \n", - " np.ndarray[np.float_t, ndim=1] center, \n", - " np.ndarray[np.float32_t, ndim=2] w2D, \n", - " float r50, \n", - " float b, \n", - " float a):\n", - "\n", - " cdef float pi = np.pi\n", - " cdef int x,y,k,m\n", - " cdef float s,dr,d\n", - " cdef Py_ssize_t fac_x = 7\n", - " cdef Py_ssize_t fac_y = 7\n", - " cdef np.ndarray[np.float32_t, ndim=2] fac = np.zeros([fac_x, fac_y], dtype=np.float32)\n", - " cdef float w2D_fac = 2 * (b - 1) / (2 * pi * (r50 * a)**2)\n", - "\n", - " for k in range(fac_x):\n", - " for m in range(fac_y):\n", - " fac[k, m] = w2D[k, m] * w2D_fac\n", - "\n", - " for x in range(dims[0]):\n", - " for y in range(dims[1]):\n", - " dr = ((x - center[0]) ** 2 + (y - center[1]) ** 2)**(1./2)\n", - " d = (1 + (dr / (r50 * a))**2)**(-b)\n", - " \n", - " s = 0\n", - " for k in range(fac_x):\n", - " for m in range(fac_y):\n", - " s += fac[k, m] * d\n", - " density[x, y] = s\n", - " return density" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 6 - }, + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "clang: /Users/uweschmitt/.ipython/cython/_cython_magic_f24e61fd7e336481e3f458d73845fd48.c\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_f24e61fd7e336481e3f458d73845fd48.c:515:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_f24e61fd7e336481e3f458d73845fd48.c:515:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "/usr/bin/clang -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /Users/uweschmitt/.ipython/cython/Users/uweschmitt/.ipython/cython/_cython_magic_f24e61fd7e336481e3f458d73845fd48.o -o /Users/uweschmitt/.ipython/cython/_cython_magic_f24e61fd7e336481e3f458d73845fd48.cpython-35m-darwin.so\n" + ] + } + ], + "source": [ + "%%cython -f\n", + "#Naive Cython implementation\n", + "cimport cython\n", + "import numpy as np\n", + "cimport numpy as np\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "def cython_pdf(np.ndarray[np.float32_t, ndim=2] density, \n", + " np.ndarray[np.long_t, ndim=1] dims, \n", + " np.ndarray[np.float_t, ndim=1] center, \n", + " np.ndarray[np.float32_t, ndim=2] w2D, \n", + " float r50, \n", + " float b, \n", + " float a):\n", + " \n", + " cdef double dr = 0.0\n", + " \n", + " for x in range(dims[0]):\n", + " for y in range(dims[1]):\n", + " dr = np.sqrt((x - center[0]) ** 2 + (y - center[1]) ** 2)\n", + " density[x, y] = np.sum(w2D * 2 * (b - 1) / (2 * np.pi * (r50 * a)**2) * (1 + (dr / (r50 * a))**2)**(-b))\n", + " return density" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%%capture\n", + "%%cython -f\n", + "#Modestly tunned Cython implementation\n", + "cimport cython\n", + "import numpy as np\n", + "cimport numpy as np\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "@cython.cdivision(True)\n", + "def cython_pdf_opt(np.ndarray[np.float32_t, ndim=2] density, \n", + " np.ndarray[np.int64_t, ndim=1] dims, \n", + " np.ndarray[np.float64_t, ndim=1] center, \n", + " np.ndarray[np.float32_t, ndim=2] w2D, \n", + " float r50, \n", + " float b, \n", + " np.float32_t a):\n", + " \n", + " cdef np.float32_t pi = np.pi\n", + " cdef np.float32_t dr = 0.0\n", + " cdef long x, y\n", + " cdef double fac, cx, cy\n", + " \n", + " cx = center[0]\n", + " cy = center[1]\n", + " \n", + " cdef float s = np.sum(w2D)\n", + " \n", + " for x in range(dims[0]):\n", + " for y in range(dims[1]):\n", + " dr = ((x - center[0]) ** 2 + (y - center[1]) ** 2)**(0.5)\n", + " fac = 2. * (b - 1.) / (2. * pi * (r50 * a)**2) * (1. + (dr / (r50 * a))**2)**(-b)\n", + " density[x, y] = fac * s\n", + " return density" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "hope.config.keeptemp= True\n", - "hope.config.optimize=True\n", - "hope_pdf = hope.jit(pdf) \n", - "numba_pdf = numba.jit(pdf, nopython=False)\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "building '_cython_magic_7c009ac0db35df252e00390b32bc6500' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch i386 -arch x86_64 -g\n", "\n", - "native_pdf_mod = load(\"pdf\")\n", - "native_pdf = native_pdf_mod.run" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "running build_ext\n", - "building 'pdf' extension\n", - "C compiler: /usr/bin/clang -fno-strict-aliasing -fno-common -dynamic -pipe -Os -fwrapv -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes\n", - "\n", - "compile options: '-I/Users/jakeret/workspace/virtualenvs/hope_benchmarks/lib/python2.7/site-packages/numpy/core/include -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c'\n", - "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11'\n", - "clang: ././src/pdf.cpp\n", - "/usr/bin/clang++ -bundle -undefined dynamic_lookup -L/opt/local/lib -Wl,-headerpad_max_install_names -L/opt/local/lib/db48 ./src/pdf.o -o ./pdf.so\n", - "\n" - ] - } - ], - "prompt_number": 7 - }, + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "clang: /Users/uweschmitt/.ipython/cython/_cython_magic_7c009ac0db35df252e00390b32bc6500.c\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_7c009ac0db35df252e00390b32bc6500.c:516:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "In file included from /Users/uweschmitt/.ipython/cython/_cython_magic_7c009ac0db35df252e00390b32bc6500.c:516:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/arrayobject.h:4:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarrayobject.h:18:\n", + "In file included from /Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/ndarraytypes.h:1809:\n", + "/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: \"Using deprecated NumPy API, disable it by \" \"#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION\" [-W#warnings]\n", + "#warning \"Using deprecated NumPy API, disable it by \" \\\n", + " ^\n", + "1 warning generated.\n", + "/usr/bin/clang -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g /Users/uweschmitt/.ipython/cython/Users/uweschmitt/.ipython/cython/_cython_magic_7c009ac0db35df252e00390b32bc6500.o -o /Users/uweschmitt/.ipython/cython/_cython_magic_7c009ac0db35df252e00390b32bc6500.cpython-35m-darwin.so\n" + ] + } + ], + "source": [ + "%%cython\n", + "#Aggresively tunned Cython implementation\n", + "cimport cython\n", + "import numpy as np\n", + "cimport numpy as np\n", + "\n", + "@cython.boundscheck(False)\n", + "@cython.wraparound(False)\n", + "@cython.cdivision(True)\n", + "def cython_pdf_unrolled(np.ndarray[np.float32_t, ndim=2] density, \n", + " np.ndarray[np.long_t, ndim=1] dims, \n", + " np.ndarray[np.float_t, ndim=1] center, \n", + " np.ndarray[np.float32_t, ndim=2] w2D, \n", + " float r50, \n", + " float b, \n", + " float a):\n", + "\n", + " cdef float pi = np.pi\n", + " cdef int x,y,k,m\n", + " cdef float s,dr,d\n", + " cdef Py_ssize_t fac_x = 7\n", + " cdef Py_ssize_t fac_y = 7\n", + " cdef np.ndarray[np.float32_t, ndim=2] fac = np.zeros([fac_x, fac_y], dtype=np.float32)\n", + " cdef float w2D_fac = 2 * (b - 1) / (2 * pi * (r50 * a)**2)\n", + "\n", + " for k in range(fac_x):\n", + " for m in range(fac_y):\n", + " fac[k, m] = w2D[k, m] * w2D_fac\n", + "\n", + " for x in range(dims[0]):\n", + " for y in range(dims[1]):\n", + " dr = ((x - center[0]) ** 2 + (y - center[1]) ** 2)**(1./2)\n", + " d = (1 + (dr / (r50 * a))**2)**(-b)\n", + " \n", + " s = 0\n", + " for k in range(fac_x):\n", + " for m in range(fac_y):\n", + " s += fac[k, m] * d\n", + " density[x, y] = s\n", + " return density" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "pdf(density, dims, center, w2D, r50, b, a)\n", - "\n", - "hdensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "hope_pdf(hdensity, dims, center, w2D, r50, b, a)\n", - "\n", - "ndensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "numba_pdf(ndensity, dims, center, w2D, r50, b, a)\n", + "name": "stdout", + "output_type": "stream", + "text": [ + "running build_ext\n", + "building 'pdf' extension\n", + "C compiler: /usr/bin/clang -fno-strict-aliasing -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -arch i386 -arch x86_64 -g\n", "\n", - "cdensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "cython_pdf(cdensity, dims, center, w2D, r50, b, a)\n", - "\n", - "c2density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "cython_pdf_opt(c2density, dims, center, w2D, r50, b, a)\n", - "\n", - "c3density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "cython_pdf_unrolled(c3density, dims, center, w2D, r50, b, a)\n", - "\n", - "nadensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "native_pdf(nadensity, dims, center, w2D, r50, b, a)\n", - "\n", - "assert np.allclose(density, hdensity)\n", - "assert np.allclose(density, ndensity)\n", - "assert np.allclose(density, cdensity)\n", - "assert np.allclose(density, c2density)\n", - "assert np.allclose(density, c3density)\n", - "assert np.allclose(density, nadensity)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 8 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print \"Python\"\n", - "%timeit pdf(density, dims, center, w2D, r50, b, a)\n", - "print \"hope\"\n", - "%timeit hope_pdf(density, dims, center, w2D, r50, b, a)\n", - "print \"Numba\"\n", - "%timeit numba_pdf(density, dims, center, w2D, r50, b, a)\n", - "print \"Cython\"\n", - "%timeit cython_pdf(density, dims, center, w2D, r50, b, a)\n", - "print \"Cython opt\"\n", - "%timeit cython_pdf_opt(density, dims, center, w2D, r50, b, a)\n", - "print \"Cython unrolled\"\n", - "%timeit cython_pdf_unrolled(density, dims, center, w2D, r50, b, a)\n", - "print \"Native\"\n", - "%timeit native_pdf(density, dims, center, w2D, r50, b, a)\n" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "Python\n", - "100 loops, best of 3: 10.8 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "hope\n", - "10000 loops, best of 3: 106 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "Numba\n", - "100 loops, best of 3: 11 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "Cython\n", - "100 loops, best of 3: 7.15 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "Cython opt\n", - "100 loops, best of 3: 2.56 ms per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "Cython unrolled\n", - "10000 loops, best of 3: 35.9 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n", - "Native\n", - "10000 loops, best of 3: 54.7 \u00b5s per loop" - ] - }, - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "\n" - ] - } - ], - "prompt_number": 9 - }, + "compile options: '-I/Users/uweschmitt/Projects/hope/venv3/lib/python3.5/site-packages/numpy/core/include -I/Users/uweschmitt/Projects/hope/venv3/include -I/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5m -c'\n", + "extra options: '-Wall -Wno-unused-variable -march=native -stdlib=libc++ -std=c++11 -Wno-unreachable-code'\n", + "clang: ././src/pdf.cpp\n", + "/usr/bin/clang++ -bundle -undefined dynamic_lookup -arch i386 -arch x86_64 -g ./src/pdf.o -o ./pdf.cpython-35m-darwin.so\n", + "\n" + ] + } + ], + "source": [ + "hope.config.keeptemp= True\n", + "hope.config.optimize=True\n", + "hope_pdf = hope.jit(pdf) \n", + "numba_pdf = numba.jit(pdf, nopython=False)\n", + "\n", + "native_pdf_mod = load(\"pdf\")\n", + "native_pdf = native_pdf_mod.run" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "pdf(density, dims, center, w2D, r50, b, a)\n", + "\n", + "hdensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "hope_pdf(hdensity, dims, center, w2D, r50, b, a)\n", + "\n", + "ndensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "numba_pdf(ndensity, dims, center, w2D, r50, b, a)\n", + "\n", + "cdensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "cython_pdf(cdensity, dims, center, w2D, r50, b, a)\n", + "\n", + "c2density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "cython_pdf_opt(c2density, dims, center, w2D, r50, b, a)\n", + "\n", + "c3density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "cython_pdf_unrolled(c3density, dims, center, w2D, r50, b, a)\n", + "\n", + "nadensity = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "native_pdf(nadensity, dims, center, w2D, r50, b, a)\n", + "\n", + "assert np.allclose(density, hdensity)\n", + "assert np.allclose(density, ndensity)\n", + "assert np.allclose(density, cdensity)\n", + "assert np.allclose(density, c2density)\n", + "assert np.allclose(density, c3density)\n", + "assert np.allclose(density, nadensity)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "funcs = [\"pdf\", \n", - " \"numba_pdf\", \n", - " \"hope_pdf\", \n", - " \"cython_pdf\", \n", - " \"cython_pdf_opt\", \n", - " #\"cython_pdf_unrolled\",\n", - " \"native_pdf\", \n", - " ]\n", - "perf_comp_data(funcs, \n", - " len(funcs)*[\"density, dims, center, w2D, r50, b, a\"], rep=100)" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "stdout", - "text": [ - "function: native_pdf , av. time sec: 0.00005007, min. time sec: 0.00004888, relative: 1.0\n", - "function: hope_pdf , av. time sec: 0.00010014, min. time sec: 0.00009894, relative: 2.0\n", - "function: cython_pdf_opt , av. time sec: 0.00257397, min. time sec: 0.00239992, relative: 51.4\n", - "function: cython_pdf , av. time sec: 0.00727844, min. time sec: 0.00702214, relative: 145.4\n", - "function: pdf , av. time sec: 0.01095247, min. time sec: 0.01038003, relative: 218.8\n", - "function: numba_pdf , av. time sec: 0.01107156, min. time sec: 0.01068902, relative: 221.1\n" - ] - } - ], - "prompt_number": 10 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Python\n", + "7.48 ms ± 175 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "hope\n", + "119 µs ± 2.65 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "Numba\n", + "185 µs ± 1.95 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "Cython\n", + "4.97 ms ± 253 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n", + "Cython opt\n", + "27.3 µs ± 675 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "Cython unrolled\n", + "39.1 µs ± 816 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n", + "Native\n", + "50.4 µs ± 695 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n" + ] + } + ], + "source": [ + "print(\"Python\")\n", + "%timeit pdf(density, dims, center, w2D, r50, b, a)\n", + "print(\"hope\")\n", + "%timeit hope_pdf(density, dims, center, w2D, r50, b, a)\n", + "print(\"Numba\")\n", + "%timeit numba_pdf(density, dims, center, w2D, r50, b, a)\n", + "print(\"Cython\")\n", + "%timeit cython_pdf(density, dims, center, w2D, r50, b, a)\n", + "print(\"Cython opt\")\n", + "%timeit cython_pdf_opt(density, dims, center, w2D, r50, b, a)\n", + "print(\"Cython unrolled\")\n", + "%timeit cython_pdf_unrolled(density, dims, center, w2D, r50, b, a)\n", + "print(\"Native\")\n", + "%timeit native_pdf(density, dims, center, w2D, r50, b, a)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [ - "from matplotlib import pyplot as plt\n", - "from mpl_toolkits.mplot3d import Axes3D\n", - "from matplotlib import cm\n", - "from matplotlib.ticker import LinearLocator, FormatStrFormatter\n", - "\n", - "density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", - "pdf(density, dims, center, w2D, r50, b, a)\n", - "\n", - "fig = plt.figure()\n", - "ax = fig.gca(projection='3d')\n", - "gx, gy = np.mgrid[0:dims[0], 0:dims[1]]\n", - "surf = ax.plot_surface(gx, gy, density, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)\n", - "fig.colorbar(surf, shrink=0.5, aspect=5)\n", - "plt.show()" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "display_data", - "png": "iVBORw0KGgoAAAANSUhEUgAAAWAAAADtCAYAAACBOK/+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztnXuYE+XZ/7+T4ybZA4fCIiyCyvlMAVFfVBAXxBYUsSpa\nQQ7FUg+lvi1offuKtgJilZ+AtUVrgVKRtraIB1YBZQEVVgSkL4JABVwQUIQ95JxM8vtj+wxPZmcm\nM5mZZBKez3Xlgt0kk5ls8p177ue+vzeXTCaTYDAYDEbWseV6BxgMBuNChQkwg8Fg5AgmwAwGg5Ej\nmAAzGAxGjmACzGAwGDmCCTCDwWDkCCbADAaDkSOYADMYDEaOYALMYDAYOYIJMIPBYOQIJsAMBoOR\nI5gAMxgMRo5gAsxgMBg5ggkwg8Fg5AgmwAwGg5EjmAAzGAxGjmACzGAwGDmCCTCDwWDkCCbADAaD\nkSOYABcgyWQSsVgMbNwfg2FtHLneAYZxJJNJ8DyPaDSKSCQCjuOQTCbhcrngcrlgs9lgs9nAcVyu\nd5XBYIAJcMGQSCQQi8VQV1cHn88HjuNgs9kQCAQAANFoVBBeu90Op9MJu90Ou90OjuOYKDMYOYAJ\ncJ6TTCYRj8cRj8cBNAlxIBBAIpEQRJXneTgcDthsNuEx4XBY2AbHcXA4HLDb7cLjyGMZDIZ5cEmW\nKMxLSLohHo8jmUwimUwiHA4jEonA4/EI6YdQKAS73Y5kMolEIgGbzQa73S78S0Sa3E9+ttlsgijT\nkTKDwTAOFgHnISTdkEgkADSlF0KhEFwulxDNErHlOA5utxs2m00QWZ7nhVxxMplsJshEaKPRaMrr\nElEmwszyyQyGPpgA5xHidAPP8wgGg+A4DiUlJXA4HIjFYrLP5zhOiGYJiURCEOVYLAae54X8MS3M\n5PXpBT6A5ZMZDD0wAc4DxOkGAAiFQohGo/B6vULkmwkk3+twOITXIq+XSCQQjUaFaJoWZal8cjKZ\nFB5DImWWT2Yw5GECbHHE6YZYLIZgMAiXy4WysrJm4qY3AiXPp7dLUhd0pCyVTybPIZE5EXZalFk+\nmcE4DxNgiyJV3RAMBpFMJlFcXAyn06n4XAJZjNMDnbogr0vnk+PxeLN8MoH8PxaLpaRHWD6ZwWAC\nbDmIsNGdbHR1g9vttoRQpcsn0+KslE+mF/pYPplxocEE2EKQFmKyEBaPxxEMBuFwOCTTDVZDnE8G\nAKfTmVE+GTgv8nTqwurvAYOhBSbAFkCcbkgmkwgEAuB5Hj6fTzHdoLTNXEePJJecST6ZbiKJxWLC\nz6TMjuWTGYUAE+AcQ3K7kUgEXq8XkUgE4XAYRUVFKC4u1iwutFBZEbl8MomSpfLJ4nQEyyczCgUm\nwDmCTjcAQDweR0NDA+x2O0pLS1Nyq5lsO58gUS2NXH2yVNWFOJ/M8zzsdjvcbndKKRwTZYbVYAKc\nZUi0RyI40kKcSCSE6gYmFOnrkyORiGw+mV7AjEQiAKTzyWyRj5FrmABnEbkWYqfTCZvNBpfLZcrr\n5ltELIWW+mT6seJ8Msmzk22yfDIjlzABzgL0IhvHcc1aiAEItpF6IXW/tBdEoSKXTw6FQkIViVQ+\nmU7vkMeITYhYPpmRDZgAm4iUY5lUCzHP84ZFqeQ1SJRNcyFEeHTkS0RZHCWHw2FV+WRSSSLVWl3o\n7yMjOzABNgmtLcR6IcIbj8fhcrmE3Cmpq1USHjPExAplcIRM88kkUiaPIflkAJKpC6scLyN/YAJs\nMEotxMSxTIzeduFoNCo0bDgcDiHyI6LgdDrhcDhShIdE5nI1uEaIiVUFSU0+mUTASvXJUvlkeqHP\nqsfPsA5MgA1CyrHM7BZiIu7xeFxIafj9ftnH08KjxtNBSngKFa31yeIoGTifT47FYsLJkOWTGUow\nATYAcbrB7BbiZDKJSCSCUCgEt9uNsrKyjL/Y6TwdSPsw/Tir50GNSn+oqU+WSuvwPC9UtEj5XRCR\nt/r7yDAfJsA6kEo3hEIhzS3EWlIQ8XgcgUAgxYRdar/0fKmlcqZKl+diT4dCRk0+GWiqP5bzu+B5\nnpnaMwAwAc4IIrzRaFT4YultIVbzmqFQSHNKw0w7SiI6dPRPRIcIU6EjlU/2+/1wuVyq88lsSOqF\nCxNgjRDBIaviHo8HgUDAsBZiKVGlF9ms4oomvjwXR4L0Qp84Eizk6I6cdIh40r8X55MBSIoyfYJn\nQ1ILGybAKpFyLON5HoFAQFgAyxS5LxK9yKY2pZGrL6U4EqQjPqUhoGZEd1aIvMV/h0zzyfR7Ix6S\nSoSYLfLlL0yA0yBlkE5aiAHoWgBTek09i2xWqcGVWuCjy+CUTHb07r8Vjj8devwuAJZPLgSYACsg\nNkinW4i9Xq8QsRgBufQkUbXSIpva7VkR2n8BSBWdbNQmm42ek59SfbL4KkK8AErnkxsbGwE0meE/\n88wzuO+++9CuXTv9B8cwHCbAEkg5lgWDQcRiMSHdkEgkDL3UpduUrTR6yGxYbbIySlcRSgug5P+7\nd+/WtS7BMJfcr+ZYDDI6h4hvNBpFQ0MDOI5DixYtTBFGkttLJBIoKytDUVGRrigq3yGi43K54PF4\n4PP54PV64XQ6hauSQCCAQCCAcDgsXKVYIfebDchVBHl/vF4vPB6P8P6Q9MV//dd/4cSJE1ixYgU+\n+ugjrFu3Dj169EDXrl3x1FNPSW77wQcfRNeuXdG/f3/s3r0bAPD5559j4MCBwq2srAyLFy/O5iEX\nLCwC/g/idEMikVBMBRhR3kUvspG0hhkVDoUgTOlqk+nRRqTSgETX2Twp5SL/Tl9FkJZzh8OBZcuW\nYdasWTh8+DBeeeUVnDp1Ch9++CE6dOiAIUOGYNy4cejZs6ewnbfffhuHDx/GoUOHsGPHDsycORPb\nt29H9+7dBTFOJBLo0KEDxo8fn9VjLFQu+AiYVDeEw2FhOkUwGERjYyOKiop05WGVXjMcDqO+vh42\nm83whTwSxdNeBYUGiZKdTieKiorg9Xrh8/mEahTSFBMMBoXUDt0mXsiQdE3v3r3hcDjwwgsv4Pnn\nn0e/fv3QuXNnOJ1O3HHHHXj99ddTnrdu3TpMnjwZADB06FDU1dXh9OnTKY/ZuHEjLrvsMnTs2DFr\nx1PIXNARsB7HskwjYLlONiMiauD8EEu73S4saJGIvtBXxsmlOcdxQqqIzpcqTWU26v2wQgUK+RzR\nzTAnTpxIEc2Kigrs2LEj5XlSjzl+/DjKy8uF37366qu48847zdz9C4oLUoDFBum0YxkZC6RlW2q+\ncJl2sqmFTmc4nU7Ba5h0WNlstma1uIW+oKWlqsDs2uRsQ/89tZxwxUEA/bxoNIo33nhDNn/M0M4F\nJcBSjmWZiqIWwTKzk40YiAeDQbjdbrjd7pT7yJePbhSRMtuho8JCj5JzVZucLeiggPzboUMH1NbW\nCo+pra1FRUVFyvPEjzl+/Dg6dOgg/Lx+/XoMGjQIbdq0MXP3LyguGAHmeR7hcFj4IhnhWEYucY3o\nZMskBUFqhmmv4VAoJOyT3PbkFrSkosJ8jJK1pgGUapPFDRHpapOtkIIgRKNR4TM3ePBgHDp0CEeP\nHkX79u2xZs0arF69OuXx48aNw9KlS3HHHXdg+/btaNGiRUr6YfXq1Zg4cWJWj6HQKXgBJumGWCyG\nhoYGlJaWZuRYpvU1jbKLlNt+OBwWzH/0lK0B6i0pL6QoOZPUhVXqbclJwO/3o7i4GEDTBI+lS5di\n9OjR4Hke06ZNQ8+ePfGHP/wBAHDvvffixhtvxNtvv40uXbrA5/PhT3/6k7DNQCCAjRs34sUXX8zJ\nMRUqXLJAl4Wl5rHV19eD4zhDRAsA6urqUFJS0syUmyyyeb1e1RUUjY2NcLvdaT0l6O37fL5mX3oy\nD47UhBJDF70Tl2kBIv9KCRB5T8PhcIp7Wjbx+/3w+XymnxzokxT5l7wmaQfOduoimUwiEAjA5/Ph\nyy+/xJNPPtks0mVYh4KMgOnqBtJCTKYOm1FWBpi/yEZvnx7oKUbKBMaIc2y6KFlsJkPeeytdkhuN\nVConEokIJ6tctlWLI2CGNcnvpV4RpJmC5OxINEAcywAYugBGBCYajaK+vt6QTjYpYrFYyvat0qZM\nxMftdgsda0VFRUI7LInWyYmj0OtwSdrCZrM1q00m6w7ZrE1mAqxMVVVVRp2BANC5c2f069cPAwcO\nxOWXX97sec888wxsNhvOnj2ruA8FEQErOZbROVibzWa4f0MwGEQikdCdT5aKVKVmvlkZOkrmeV6w\nSqQrDOgo2aw63FwijvjJAh99P53OMbo2mX79QCCAkpIS/QdVgPA8j/vvvx8bN27U3BkINP1dN2/e\njFatWjXbdm1tLTZs2IBOnTql3Y+8F2BxuiFdC7ERX1ByqZlIJOBwOFBSUmJ4uoGUlpGmECtEvJkg\nVWEgNd5ILpes53WtiLhtGDB25BMtwPkYAZv5d6O/+zU1NejSpQs6d+4MAEJnIC3Acp2BpDJETkse\neughLFy4EDfddFPafcpbAZYySCeXdXI5UiP+uPQimN1uNzQdQL6IgUAAiURCc1MIYFzO1yzo6Fc8\n3ihbUbLVUHpPSIBBFvjkbCilyEcBBoC3PN0N3+b3Qp+n/JxpZ+CJEydQXl4OjuNw/fXXw2634957\n78WPfvQjAMDrr7+OiooK9OvXT9V+5aUAk7ZSIjRqW4j1iJPUIpvf7zdU7GKxGEKhkGFVGvlCuiiZ\nNtqx+hBQErnqRS51oWTWTi9+Ak0piLZt2+rel2xj95hQzhdK/THTzkDCtm3b0L59e3zzzTeorKxE\njx49MGjQIMybNw8bNmxI+3xCXgmwlGMZaSFWU92QqQCbPZONiAzHcbrnyhUCWiJCufE9hYaW2mSg\nKRI7duyYZI7S6tg9+v+On0b8+DQSkL1fb2dg+/btAQBt2rTB+PHjUVNTg5YtW+Lo0aPo37+/8PhB\ngwahpqZG9kSYF59YKceyUCiExsZGuFwulJaWmlJalkgk4Pf7EQwG4fP5UFxcnPIF0Hu5T6LqhoYG\nwf/WKPGlz/BWTkmohUSEtEewx+MRor5IJCJUXAAQSsCyTTbL7sgJyOVyoaioSKi4sNlsOH36NLZt\n24b7778fl112GR544IGMV/zr6upw6623omfPnujVq5ewEGUWzhK77tvg75RhWof2wk0M3RkYjUax\nZs0ajBs3LuUx48aNw8qVKwEgpTOQuCUCTVcZ7777Lvr27Ys+ffrg9OnTOHLkCI4cOYKKigrs2rVL\n8SrE8hGw2LFMTwuxWsFU28mmR4BJ2oTYURo13khc90z2Mdv1uGaLPh0R0lFyPB5HJBIpCE+HTCDv\nyYwZM3DkyBEsXboUJSUl+N73vofq6uqMVvx/+tOf4sYbb8Tf//53YQ3ETOwu8+NCPZ2Bp06dwi23\n3AKgSY/uuusujBo1qtlrqPmcWVaAxY5lpORLTwuxGsGUs4s0CnIc0WhUOA6jBCGRSAhXCR6PR0jZ\nkHrobC9sZVvoyPFxHCccP73AJ26MsHIuOVPEVRClpaVoaGhAz549M1rxLyoqwtatW7FixQoAEAIf\nM7E5s5OCGzNmDMaMGZPyu3vvvTfl56VLlzZ73qWXXoo9e/ak3f4XX3yR9jGWE2DyhfH7/UJ0Q/se\nFBcX6/piywlwJp1sWiNgkkt2Op3None96YxoNIpAICAsZjkcDqEZhed5uN1u2fKvfDTcUYNclKy3\nukCJXHf+0Z8hv9+PkpIS7N+/P2MvYLvdjjZt2mDKlCn49NNPMWjQIDz33HNCY5MZOIsunDUQS576\nSaRCDHTi8ThKS0vh8Xh0m85IYXYnmziX7PP5DIu66G0XFxfLnjhIdEgmSJD9oD0jAoEAgsGgMGfN\n6MGjVkAul0xG+ZBccjAYFFIZ+fY+iBsxMl3xJ917u3btwk9+8hPs2rULPp8PCxYsMHyfaWxOu+E3\nq2K5CJhEgkSE6TEzRm2boMUuUs32xIi9epUaKkhVh1rktk2vhKvZf6nyL3pVHYBh0WE2yMSKUqm6\ngExlBvLjfaDL4AKBAIqLi3Wt+CeTSVRUVGDIkCEAgFtvvdV0AbY7LRkXmoIlj5TkK8lkB6OgF6TE\nM9mMdu3ieR6NjY0Ih8MoKSmB1+s1NNfr9/slt633CkG8qq4UHeaq0sBs6PeBnjqsJkrOdQqChrSD\n61nxb9euHTp27IiDBw8CaJoJ17t3b1P32+5yGH6TQo8XBND0/g4cOBBjx44VfldTU4PLL78cAwcO\nxJAhQ/Dxxx8rHqvlImAAgmevGUMlE4mEMGZe7yKbVNRqtFeveNt0dYbefLgaxItUdHR4odTjaomS\nycKnw+HISZQs50Whxwt4yZIluOuuuxCNRnHZZZel3GcG2YiA9XpBAMBzzz2HXr16CSVpADB79mz8\n+te/xujRo7F+/XrMnj0b77//vux+WFKAyQfeSMgXIxaLwev1muIoRldQaG2oSJfOkJp+YcR2tUJX\nUgCpHVp0pQFNoS3uAfLvA2kM0jJFwwzEf/NMV/wBoH///mkjOSOxOczP2er1gjh+/DjefvttPPro\no3j22WeF51x00UWor68H0FQ/TY90ksLSAmyUcJBcKTFAKSoqMmS7dEpDjVdvJtBRr9qIOpsLRnKV\nBqQhQsrboRCnadDHQ09kzvaoJ6kION+wOcyPgPV6QfzsZz/D008/jYaGhpTnLFiwAMOGDcPPf/5z\nJBIJfPTRR4r7YUkBBoyJ3MSLbCQ9YBSk6aG+vt6QNmXx8dINFWojaiNywVrY0mowAOCasztT9oHk\n8EneNFslcLnMwUpVEeRq1FM+VW2IcbjNl6VMK0OSySTefPNNtG3bFgMHDsTmzZtT7p82bRoWL16M\n8ePH429/+xumTp2a4g0hpiAFWK6TLRaLGbZ/dNNDcXGx7sVCceswySObMV3DDKSEmCDl7SAnRLm4\nXDcapX02eyAqOQGRz04+YkQKYvvJM9h+8ozs/XoqQ1577TWsW7cOb7/9NsLhMBoaGjBp0iSsXLkS\nNTU12LhxI4CmipHp06cr7qclV0v0pCDi8TgaGhoQjUYlKwT0RgZE3Ml8ObJabhRk/2OxGEpLSy3v\nijZsXmoLJhHidNDTNMjkCHKikZocQWbQFRpSlSderzfj+mwiwPlqRQk0CbDe21Udy/HQ5b2Fm5hM\nK0PatWuHefPmoba2FkeOHMGrr76K6667Tnhcly5dUF1dDQB477330K1bN8VjLZgIWE0nm14B5nle\nmIBRUlKSkus0AlK6li9R78kZP0D5d7sasi2lxT2p0fBWbCM26gRhRJSc1wLsNF+W9FaG0NDv+7Jl\ny3DfffcJOrRs2TLl/TDukIxFi1iabRcptxBm1DwvYjCUTCZ17z/9vuUqYtzSajCGnNiqaxtypV9y\nlpREiHIdJZtx0lSbSyavfezYMezfvx8+n8/wfckG2aiCAPRVhhCuvfZaXHvttcLPgwcPbraYp4Ql\nBVicD5X7UGvtZMskAs5kIUwtdNTudrsRi8UMOXnQZVBaO+wyYdi8Udj2y3dNfQ1A2aScjgw5jkMk\nEjFsvJEVkYqSeZ5HOBzGJ598grlz5wrWiJ06dcLWrVvB8zymT5+OOXPmNNvegw8+iPXr18Pr9WL5\n8uUYOHAggKbhk+Rz73Q6UVNTY/6xZUmArYAlBRg4L8JSAqzWLlJqm2oFWM1CmJ6URiwWQyAQgN1u\nR1lZmRDV6YXkSomLHInSg8FgszIwM/m4w9W46mtzfWOlSuDIpGHgfAmcGVUGUuSyAoO8DxzHYcKE\nCSgpKcGOHTtw1VVX4d5778WOHTsMHz5pFtkoQ7MKlhVgQPpyzgi7yHRfFLFXr5EpDbEdJVnA0xul\n0icMjuPg9XoFMQ6Hw3C5XILIG1GXe3LGD3Ttr1kQIXK73QDS50+t7Ough0AggPLycpSXl2PgwIEZ\nNxwA2U9l2Qy2BbAyljzVSFUtEOFqbGyE2+3OSHzVNDAEAgH4/X54PJ5mEzCktqflwxmLxVBfXy/k\neunqCT3RNF05QcaQS7Wj0g5gRUVFwvj4UCgkTJPQUnFAL8CJqyGsQroqg0JwPyPQgQWxopRrJqBR\negzHNQ2fHDx4MF588cUsHAXAOeyG36QwwwviF7/4BXr27In+/fvjlltuEbri5LCkABOIKBlpFykn\ndOQ1AAjiaFRURCYdBwIBeL3etMKuFpJDpk9KarZLRIm2pvR6vYqmO5kI0odtr8jksHShJg2gtgQu\nHA5rOiHl2oiH3kciwJk2HBC2bduG3bt3Y/369Xj++eexdau+xVU12Ox2w29iiBdEVVUVPvvsM6xe\nvRr79+9PeQydmlm2bBlmzpyZcj/xgqDf41GjRmHfvn349NNP0a1bN8yfP1/5WHW8T1khGAzKzmTL\nBLEA6/HqVRO1RqNRoV1RHPXqged5xXphrUJA8qi0KJGTEMlXBwIBoRZVCqtGwemgo2Ta/Uw8by4f\nXODI3z0QCMDn85kyfNJsbC6H4TcxtBeE0+kUUjM0cqkZAIIXxPTp01M0oLKyUtCPoUOH4vjx48rH\nquudMhHSZcZxnCl2kXRDhV5LSikRlhJ2JVFUm4IgUW9DQ4MQ9ZoxRVkubWGz2XDmvjsNfz0rQS/s\nFRUVSZ6QgsFgygmJlMflOgKmBbi0tNSU4ZNmw9ntht/E6E3NEC8IpWDt5Zdfxo033qh4rJZdhIvH\n44IAGPmhJv4NmTiLSW1LCtK95HK5VFdoqIGMauI4Zbc1M/KXUrWoatjSarBke3K+IVUCJ+VvwXFN\npvi5HvFEGjGyMXzSaKQE0/DXMMkLgvDkk0/C5XLhzjuVgxVLCjCpcPD7/YaKCakbDQQChnn1ksiV\n1NsGAgHBH0JLRK0UAWvxhjC6+08rUjXB4XC44FzQpPwtSAkcWbcwy2hHDnEETDrhzB4+aTScAVe7\nWw9+ia2HvpS93ywvCABYvnw53n77bWzatCntflpSgAlGigcpX0smk/B4PIZZUgLn0xlkPJCRRulq\no14rU9N+GC7/altWRvvkeiHMbrcrlsAB2RltRFIQ+YgREfA1PS/BNT0vEX6e//YHKffTqZn27dtj\nzZo1WL16dcpjxo0bh6VLl+KOO+5o5gUxb948AEB1dTV++9vfCuJbVVWFp59+GtXV1ao0xtICDOi/\nnBZ79UYiEcNblY1IZ4ixqiNapvW/5MNIBEnO36GQOtfkWojN8regTz6NjY156wUhVzZmJGZ5QTzw\nwAOIRqOorKwEAFx55ZX43e9+J7sfXNKiBY9k5Z0M5tSzDYfDAa/XC5vNBr/fL6z260Ec9Rox8+3s\n2bNo2bKlkMoAAJ/PpynqTSaTOHfuHMrKyoRqhVAoZJgvAC3ASkY84jSEXB6YbiUm4qTnsj0SiYDj\nOEMd6tQSiUQAQNNnSxwly414UnP89LGPGTMG1dXVeXfFxHEcAn+aa/h2fVPmWrK229IRcKaCRntE\nkAkV9Db1/iHoRTzSdWVU1KY36qVbuK2E3GIcWdwqlMnMmfy91Ix4ogVZ7iqBfB4JVnKK0wLnuHA6\n4SwvwFotKYkzmtEVCGT7Ylc08UiSTOF5HgCEul6rRy5G2VCKUStIhZy2EPtb0Mev1EpOUhDkPctX\nslEFYRUsK8Dkg6j2gyT26pXLxWYaAcsthumNqGlRB7SnHOSIx+OIx+OGWjRqyf+SpgxXh/Z4b/Ly\njF9TrSCRtEUikRA6+rItyuII1CjkrhLEJXBA0wn8448/hsPhyN+TEhNga6BG3OS8evVsU7x9sxbD\nxFaXDQ0NurdNji0UCsFmswmX8ESksnkJ7+rQ1EV13Yp7mn7xxlLEx96ve7tq0hbE2jMf0hZakSqB\nSyQSCIVCOHPmDBYsWIBdu3Zh4MCBqKiowOeff45kMqnZihJo+owOHjwYFRUVeOONN7JzgBdQCsLS\nSaJ0YhmPx9HY2IhoNIrS0lJ4PB5VXzK1AqxmPFAmETAR9YaGBrhcLqGbTW80TfYXgOBv4PV6AUBo\nqw2HwxkZ71gZupWYbil2OBwprcSkGsYoI30rQU4wnTp1QlVVFYYMGYLnn38e27dvx/r16w31OzAd\nu934mwSZmvGEw2EMHToUAwYMQK9evfDII4+kPGfJkiXo2bMn+vTpI3nCo7FsBKyUgqBLy7RGpWoF\nWu2Yea2iaYbBOx2le71eBAIB4XKc7LfT6ZQciFmIpWAkZaE2bWFUk0Sua5DJ65MuOI7jMGjQIFx2\n2WUAtFtREr+DRx99FM8++2z2DiQLKQhixrNx40bNPslFRUV4//334fV6EY/HMWzYMGzbtg3Dhg3D\n+++/j3Xr1mHv3r1wOp345ptvFPfDsgIMSIub2Mhca85NTVRNBMxIL2CtqRK1kNw0vb/BYFDxOXLT\nFJTE6fSPb9e9r7lEKW0Rj8fzrtpCCdIFJ+VlIB6XI+d3UF5eLvgdGLXQrBqb+QJMm/EA2k9O5MqS\nXEUSw/oXXngBjzzyiHDib9OmjeJ+5E0Kgvbq1WPpqBRVE/ORoqIi1dtXEwGTYZuRSEQxVaIlmhab\n8uhxiiPi5Ha7BeMdt9sNm80mzKvLhFCfYRk9Tw9qo1A5BzQ9aYtcpzWkImC1zxP/TPsdZP24HE7j\nbyIyNeMh7mY8z2PAgAEoLy/HiBEj0KtXLwDAoUOHsGXLFlxxxRUYPnw4du5U9kGxbARMf3hI5Oh0\nOk0Zukk3bORL1GvWnDpAuhSs0dBXsB7pqi3UejvkKmIWewEXFxeb6ndgKgZ8nrfs2Y8tnx6QvT/T\nkxN5nt1ux549e1BfX4/Ro0dj8+bNGD58OOLxOM6dO4ft27fj448/xm233YYvvvhCdvuWFWAgdUVf\nzdBNNYijaqnxQJluj4Zu1tAikkrRhlpBN9qAh+M4XDxuRMrvIml8TuVwGFQJkQ3Upi3oicy5joI5\njkNjYyNKSkpM8zswm6QBKYirv9sHV3+3j/Dzk39em3K/Xp9kQllZGb73ve9h586dGD58OCoqKgQH\nuSFDhsBms+Hbb79F69atJffTsikIMr4HAEpKSgzzAybiRCZgJJPNxwPpga5wcDqdmsRX6axM/IUj\nkQhKSkqALKa6AAAgAElEQVRUV3wYwcGT+oeFFgJyaQtSYUL+9rmotpByQqP9Dnr16oXbb79d8Dsg\nngc33ngjLr30UnTp0gX33nuvrG9BNiP7pN1p+E2MHp/kM2fOoK6uDkBTcLhhwwahdO/mm2/Ge++9\nBwA4ePAgotGorPgCFo6AnU6nYElpJOSykhil6xV2OtrMNOpNhxFOa3pW6Ht/kjoLTE30y4++Tfa+\nWCxWENaU4rQFsTklnzE6bSH2djATI6woaa699lpce+21xu6kElmogtBjxnPy5ElMnjxZqCa6++67\nMXLkSADA1KlTMXXqVPTt2xculyvtVYNlBZhc/hl5OU2M0gEY2qZMRz56cr3iY6U9LTIdQmpFgTNz\nOnGuS8FIlKw2bWHGcZMURL5iRApCDZmenPr27Ytdu3ZJbtPpdOLPf/6z6n2wrAATjBBgWsh8Pp8w\n1t4ISDrDZrMZakepZ6qGlUQ31GcYPP+3LeV3YmtKraYzVkVK/NN5W8RiMeFEZNRxB4NBtGvXTtex\n5JKERMqgULGsAJMPoB4Bps153G43ysrKhN/rhSyIkWkPpaWlhogFKbeLxWKap2qIt2N1lJolxJfv\ner1yrYKWagstaQta/EkVRN6SpQjYClhWgAmZCjDx1BWb89AVEJkKJr1tj8cjeLjqhVRlmOHkZiXk\nKiGUqg7I4EspFzArvE96Tnjpqi2Iz6/atAUZSZ+vZCsFYQUsHU5odUQDUqcdk8iUTgvobTUl23Y4\nHMJCm95ok0S98XgcLpcr7QRlNdCipYdcVkCIqw7oycw8zyMUCiEYDFrK18KIk4HUcdPVFmI/D5K+\nEVdB5CsJzm74TQozvCDOnj2LyspKdOvWDaNGjRKqJeSwtAATtFhSNjY2IhwOo6SkRHZKRSZRNSkD\nI9s2qgwsHo8L5XDETEYPJHoKh8NCRxfQ9KGxikhlCi1MZFy8uHuNnCTpAZn5Dp2yKCoqgs/nEyp4\nSJqNHO+SJUtQX19vePVQNknYnYbfxBAviKqqKs1GRcQLYs+ePdi7dy/ef/99fPBB08y5BQsWoLKy\nEgcPHsTIkSOxYMECxWO1vACrNc8R196mWwzT0vIrjnrFEXUmX3K69dnj8RgyyJOcgJLJpGBSRHrW\niUcuabENBoOqalXFJWhWQixM4mMlC5lqj1UP2a6+oNvHvV4vnE6nkJY5cOAAbr75ZpSXl+Piiy82\n3O3LbJI2u+E3MbQXhNPpFLwgaOS8IAA084Jo2bJls+dMnjwZa9emNoCIsbQAq0lBENHRYkmp9oti\nZtTb0NAAnudRVlZm2Hw6cgISL9qQyJF8WemuPzNESlwDnE1PCLEwkWPlOE5oOQ8EAgiHw4jFYkID\nRSFgt9vxk5/8BG3atMGRI0dQVFSE119/3ZAIb9u2bVIvaQrZSEGY5QVBzHoAoLy8XBBsOfJiES6R\nSDT7vR6j9HSiLq6eUIpOtRroKO1zpqmRYDAInueFxUYyjFOOdItdtBtavhcEkWMlSJm3A/rrcq0k\n4pFIBHv37kXPnj2FDi2j3L6yQcKmX5Y+qNmJD2s+kb3fLC8I8WPTvU5eCLD4TSCWkRzHZdRxpiR0\nctUTejHDQIdEdCTtkml0LlWrmkgk8O+vE+itey+lMcsTIp0QaqnL1dogkstqjGTy/DikZDKJkydP\nZmRFefz4cZSXl4PneQwaNAj//ve/MXPmTCHCywZyi2ZauHLoUFw5dKjw8zO/S02lGe0F8cknn2D4\n8OEoLy/HqVOn0K5dO5w8eRJt27ZV3M+8SkEQC8bGxka43W5hkoQRpKueUNrHdNE0nZ9Ot89qIilS\nNREIBIQFGSMduYhI5Stam1bEC1wkp5pJzjzXkH0zKsI7fvw4tmzZgs2bNxu6n0okbHbDb2KM9oIY\nMGCA8JwVK1YAAFasWIGbb75Z8VjzJgKmjdL1RpBSLb9mRL30dtXss5oURDweh9/vFxYE5Qr0zRSJ\n/WN/g55v/I9p2881cob1iURC1rA+1y3Q9OtzHIeKigpT3L6ygRERcDrM8oJ4+OGHcdttt+GPf/wj\nOnfujL/+9a/K+2HuYRoDWWhLNx5ILUTotOR6022Lht6uUT7AdP7Y6/XqXrjLlD0Dfwyg8EWYRimP\nTPwdiACSYaDZnqZBC3AymczYipJEeA6HAy1atBAivMceeyxrx8Jz2ZElM7wgWrVqhY0bN6reB0sL\nMIl6k8kkWrRoYVgbKlnY8/v9pka9Wrcrt+BotgG7HEaWoEl5QuQrUnnkWCwmNL6YZTSkhng8LpgB\nmRHhZYNsRMBWgUtaOKFFOn1CoZBQZ6eXZDKJxsZGxONxFBUV6S4tSyaTOHfuHFq1aiWUdJHRPlq3\nGw6HwfM8fD6fsG0SSWup9PD7/YLPAMdxgk2iFuE+eDLWTIA/6vMgPM5oyu+komA5K0opAQ6M+pFh\nPg8kN25EJ6FWiPjSRkN0tYXZg08DgQA8Hg/q6+sxc+ZMvPXWW4ZtO5twHIdDh+UnSGRK1y6XWjJ3\nb+kImNSqhkIhQ7ZHolOe51OaFIzA7/cjHo/rMtCh0ZuXFucEs4WSD7AU5LJdyudBz4y7XKN28KnR\nPsF+v184gecrvLVlyVDypgpC79mLrnDQUjOcjng8Lvy/rKxMl/iSYyXTOrRUY5jNR30elPz9/rG/\n0bVdKZ+HeDyOUCiUVw0T6Rbh6AYRevApx3HC4FM9x0teP999IAAgAZvhNyky9YKora3FiBEj0Lt3\nb/Tp0weLFy9u9rxnnnkGNpsNZ8+eVTzW3H+z06BXKKVMzUOhkCEGOmSeHABZ3wmt24zH44ZG0tnA\niAW5dPW5hTQ2HlB3vGrzyPRnOd+d0AAgkTQ/LiReEBs3bkSHDh0wZMgQjBs3LqVRhe4U3LFjB2bO\nnInt27fD6XRi0aJFGDBgAPx+PwYNGoTKykrhubW1tdiwYQM6deqUdj8sL8DA+chQ65eNzsnS9o5y\ni11qoUvBysrKhNl1eiBRHwDdk5k5jhNW6EmJlJ4Tjlz0ayZSvrl0TlWqYSJfxRhQPl5iNJTOsJ7j\nuPz3AgbAJ81fhKO9IABtnYLt2rUTDO+Li4vRs2dPfPXVV8JzH3roISxcuBA33XRT2v2wfAqC/KtF\nQEiFQzAYRHFxcbPo1AgDHa/Xi+LiYiEq0WMaT7bpdrvhcDh0iS+JoqPRaIr4kpFJahzR5CwoxQtw\nNGpSEXo9IZQcwcjcPAA5aZgwow6YHC/ta0HEWezhATQtBBaEAMNm+E2MXi8IwtGjR7F7924M/U/X\n3euvv46Kigr069dP1bHmVQSsBrmoN9PtEehGEL0RKoHnefj9fnAch7KyMsTjcV3+vWR7yWQSbrdb\nEAWyGER8dEk0pbQqTyogtES/WhfgAH0tyWJPC+IRDEByokYhRMlSHh5kHWLu3Ll44403cNFFF6G8\nvBw2mw0LFiwAz/OYPn065syZ02ybDz74INavXw+v14vly5dj4MCBqK2txaRJk/D111+D4zjMmDED\nDz6YvasgI1IQO3dswyc1H8jer7dTEGhK99x666147rnnUFxcjGAwiHnz5mHDhg2yzxdTMAJM53qN\nzJ+KGyCkGkG0CjqJ2EKhUEp5mZ7InN4eqUklBt5kQYcIMmniIDlHsVhZ/MJIFvIe0scnZTKUzQnF\nZkK3jPM8jyeeeAKtWrXCF198gXfffRfvvvsudu3aZXiO02yMEODvXn4Nvnv5NcLPLy5dmHK/Xi+I\nWCyGCRMm4Ic//KHQbvzvf/8bR48eRf/+/YXHDxo0CDU1NbKeEJYWYLUpCK0DLNUKnRkNEFrbk7Vs\nr6SkBKPv2AkAWLeib0qHFi3AdP5bSpCBzPK+B1390C26V9fxGImcyZDUqB+9I45oM5xcYbfb4XQ6\nMW7cOHTo0AF1dXWm5DjNJp4w/33U0ymYTCYxbdo09OrVC7NmzRIe37dv3xT7yUsuuQSffPKJopOc\npQUYUPYEzjTqVWOgIxWhZro9Ap0ekWt71hIB0ycej8cjiC8AjJv8r5THvrGynxAJAkgRHHqmnZ5L\n9C/OlKJbacZPNx05QSaiTFtT0s0hVk9b0Plnv9+P0tJSyfylFjc0gjjHmQ2yUQWhp1Pwgw8+wKpV\nq9CvXz/B7nP+/Pm44YYbUl5DzefG8gIsh56x7UqQBbxkMmlY1Es6tNKdKLTkpYLBIGKxGHw+H8bc\nKd2XTjN2UmpkSgSZ5A8LIUeqdSGMFmSymKenFMwK7x1ZhGtsbFT1eC05zmzBJ7PzPmbqBTFs2DBV\nVVRffJG+oy8vBJiOMI3I9RptoKMUAdOevUacKOjFwJKSEoy6/eOMtiMW5Df/3B/xeBzHzuqLPqoa\nhuGGUnnPB0lPiM8/ALr/l67XNQItpWBWqkWmxZ80YpiR48wWfBZSEFbB8gJMpyCMinqNtqOUE/RQ\nKIRIJJIyAkjrdujt0WmR7/1wj6Z9TMf37/4UAPDcM30N3a4SG7v/AgAwPKnePSrbiD0q6AiZriYh\nv8/1VQRpxOjVq5fhOc5swWchBWEVLC/ABFLraESFAy10avKyWiHlYEaVrMkttJlFQ8Rj6vZDfYbh\ng9iVpr6GWUiVgvE8LxgpkauTbJa+iSNgEkSYneM0i0SWUhBWwPICHI1GhdVqI3O9gHEGOnSVgZbF\nOynEEbDYYc1s8ZVDqQlDK//45mqUt4in/vLzD5DsdlXOL+e1QgTZZrPB7XbDZrM1K30zymRIDikB\nBszPcZoFn8jOZ6CqqgqzZs3SXCcNAFOnTsVbb72Ftm3b4l//Or/gXVNTg/vvvx+xWAwOhwO/+93v\nMGTIENl9sHysT5zLHA6H4QY6RNSNci9rbGxEJBJBaWlpRibs9OPJwl0wGITP58PYSXtNF1+j0g9V\nDek73k7XnT/3b+auBwAEg0HBjCZdt54UuVwIo0cB2e12WZMhvaY76YjFYnnjISJHPMEZfhNDvCCq\nqqo0T40GgClTpqCqqqrZdmfPno1f//rX2L17N5544gnMnj1b8VgtHwF7vV4hl6oXunoAgGFj5smo\nGo/HY8j0C7LQZrfbdS20ZZMvzuivPyPde7k2Nc8Uua5Ls02GxDXIVn6P1JCNCDhTLwgycPPqq6/G\n0aNHm233oosuErxh6urqmo14EmN5AQYy926gIdUIZJaaEQY6dEUGSRHohRjGm7HQpoatB1qi/yXh\nrL8uADj+vQOxSy+Hw+GAy+USokO904qtRCYmQ2qP08p2nVrIRg440zrpEydOCE0qUixYsADDhg3D\nz3/+cyQSCXz00UeK+2H5FASgT4BJ1Ov3+w0z0AGaBL2hoUHoJDPCNtPv9wMASkpKsi6+Rlc/yKUh\n/vHN1ZK/J2kIAp2CcDgc8Hg88Hg8cDgcQklYIBBQbTBkNnrSH2qmMpOrQCmTIfFr59tJSUycN/4m\nxggvCCmmTZuGxYsX48svv8SiRYswdepUxcdbPgLW82FSMtDR47sgLi/T6y9ML7TF4/GcLbRlm9N1\njmaLccSQiK4goFukAaSsB5D7SEkYAMEJLh8jZEB5moaUyVChRL4EI1IQn+3ajM92b5a9X2+dtBw1\nNTXCUM5bb70V06dPV3x8QUbARCQbGxtRVFQkRL1Sj9NCPB5HQ0MDeJ5HWVmZUNurR8zJQltxcTHG\nTtqLH8w4qHk7ehk+oakkLJfpB4Lny134wYyDuGXafnAcJ3g20JEf3UJMLtfdbjecTqdQk6smcjQK\nswWQVFrQtpTEFIos5B06dAgPPfQQbDYbTp06lfG0B6Bphb+8vBx9+2avJpyGT+i/dR8wHOOnzBVu\nYmgviGg0ijVr1mDcuHEpjxk3bhxWrlwJACl10kp06dIF1dXVAID33nsP3bp1U3y85SNgQJvA0RaP\nSq3EWhc50jmiaYU2dS8tLUXlbTW6tlcIbOauT2nKEPtZrFvRVzJCBiB0qwGQjB6zYU+ZrWibCDKB\n+D+0bdsWGzduRM+ePREKhbB//35UVFRockIDmlb4H3jgAUyaNCkrxyMmzpv/PuqpkwaAiRMnorq6\nGt9++y06duyIJ554AlOmTMGyZctw3333IRKJwOPxYNmyZYr7YempyEBTbjQajeLcuXNo2bKl7Idc\naw0uMUBP16FGO6L5fD5JQY9EIojFYqr65cVifuNdu9M+x2xI/lcpAk5XByxXBUG3JUvlf8UpiHN+\nB5b9tlrxtQi0IJOTtNPpTLkspz2Ryc9GTyomVzK5MkInE5G//PJLzJ8/H/fddx9++ctfCpHYggUL\nAAAPP/yw8Jwf//jHGDFiBG6//XYAQI8ePbB582Zhgeno0aMYO3ZsSo1rNuA4Dn/cZLwkTRupfyHf\nDPImAlaCiKQWAx01jmhqvSHURujihTYr5Hqb0g9+bD3QMievL84DtyyOY8bPr1UlwnIRciwWS/H7\nFVtwSkXIYr9gLYKcayMe8vrkJHDy5MmUS1+jVvizBZ+7HpCskxcCDEjPhdNjoKOE1CBPvdALbS6X\nK6fiy2nsxMo0+tWDeB+TKjqzpASZOL4pCTLHcSlXQnoFOVc0NjZqaqfXusKfLXQMhck7LC/Acqbs\nZhjoAJm5l6Uz0aGtKG+Y+Imm/TQasbCNv8pv6uulc0eT40cPXY0Xn90q/GyEIL+xsp8wdZoWZNI+\nTKMkyOKmiVxCf+6MckLLNXHeeqkCs8iLKgiguYFOfX097HY7SktLM4pQxaJJhDIQCAgDH41YaCMN\nH6WlpTkVX85mayZi144fiq0HWmYl/SBX/5sp5HikjkuOsZP2YvzUz/CDGQcxYfoB2O12wUiHVBMA\nEASZ3AAIrcXE74FuKyZdmrn0TyApiJKSEtNW+LMFzxt/k8KMSpFf/OIX6NmzJ/r3749bbrklbcNX\nXglwumnHWiECTMrLSA5Zay+9lJiTMjiPx4Ob7vm/nFY5yAnUqRMNKT/nqgSN9oUAmvLAAMDZOHA2\nlZ7MBgoyWVQlgkr+vlKCTHweSMOPmT4PUtBpOZKCoFf4e/Xqhdtvv11Y4Ser/DfeeCMuvfRSdOnS\nBffeey9+97vfCducOHEirrrqKhw8eBAdO3ZMWf3PBkaUoYlvzV7DJC+IUaNGYd++ffj000/RrVs3\nzJ8/X/FY8yYFQVIORk3AIIIeCoUMLS8Tz5Ez28dBTmySiURaIerTt7UZu9QMNeY8UkyfNQwv/b9t\nzUQ4mUgvapzNpipNQSM1NYSeVE2nHYgQE4ElbmjA+dZi8YgjPTPn1BAIBIQoNlMnNADNfIOzTTxu\nfgrCLC+IyspK4f9Dhw7Fa6+9prgflhdgkhpIJBIoKiqC1+s1bLukY0rv6CESIUUiEWFB0Ol0miq+\n6cTV5mh+PES4bHY7ug5SLhCn+cdmF24ZbpwdpV7UCLJW8ZVCzRgnm82WMoGa4HQ64XQ6wXFcM+Md\nIwVZahpGvsNnIQdslhcEzcsvv4yJEycqPsbyAgycn/Zq1Hy2aDSKcDgsuI3pjUjI5WkoFMrKQpuS\n+CpdsnM2DnanE5f1v0z1a62r5uF02HWJ8K5/hdCjW2YnzumzhmHFCzWIReRfW3zMCanmfwMQC/Lr\ny/sIokqiXiKq4nyww+GQFWS9Tmjk8WQaRr6TjVS62ZUiTz75JFwuF+68807Fx1legDmOg8fjMcRs\nha6cINvUK76kagKA6R1taaNewfKw+SfYrjGvva66ScScVCStR4QPHAwqirBUPfA5//mPp9Od2jAj\nJcgkEs6kYiITbrrn/1J+JnP1pAadEhtKAnF8A2CIExrAImCaI59V4+h++VpyMytFli9fjrfffhub\nNm1K+1jLCzCgPJpeLeLRQ7FYTPiiZALd0ZYN60i14gsAHJf6WFq8OvfpDEA+/0uEV45/bG7aFhFi\nM2qAxUyeeTlWvJB6YqOPKRaJKuaFsyXIZK4eQUqQSRkbbTCUTCYzFmS5aRj5TDyu/+/TsdvV6Njt\nfOXN5n/+OuV+ulJE68w8JaqqqvD000+juroaRUVFafczLwQY0Gd4Q0zY6dFDegTdKgttQKrwihFH\njS3atpJ97LEvAzj2pfp9ynZeeMjIfti38wgAIFjfNHKd/0+qwWa3A9TbwMeUT6z0+2mWGAPygkyb\nzdNDP8UWnC6XK8XAXWoqM/0ZbmxsLAgBzkYO2CwviAceeADRaFRYjLvyyitTKkzEWN4LAmi6zA8G\ng+B5Hj6fT/XzaMMbr9ebUjRPrCrLyso07Yt4oc3MjjYtUa8Yl8ed8nPZd1qiRdvz0ao4Aj72ZUBy\nO06JxTxCQ30Y1/xXC8V9BJpywASlNISULwThs4NNJXK7tx0QfhcJhJCOdGJspgCn480/9xcW9Whh\nlbriI34W4okaiUQCHMfhlVdewebNm/H73/8e7du3z9kx6YXjOMxZlv7vqpWnZngs6QWRF3XAWlMQ\n4jpcOTtKLZAaZLLQ9v27P7Wk+Lo8bknxpRGL755dX2ewh+qgxTcddD3wWxsb8eH2c8LPvbo1Xc4N\nHNYDLdo0HY/b5xFuYhI8jwTPC7XE4priZCKRU/EFmiLkm+75P0yYfgA/mHFQSEGQrjuxhSYRXBI9\nFxUVCd7ItbW12LNnD7p27Yo+ffrg0ksvzajBQE1zgtnE4wnDb1al4FIQtB2l0kh4LYJOtydnwzoy\n05SDnPCGg2G069xW8jlK4psu+gWALR/UqYqCtfDWxkbh/x9uP4dY9HwU26Zd0yU2EeG6b5pEmohw\nPBJNWzGRTCQzqhM2G3HK4q1VAwRzIXGEnEwmhciZ4zj87//+L7Zv347du3ejb9++eOedd9CjRw9N\nVpSkOWHjxo3o0KGD5HOzAX8BufHkjQADysbXWu0o1QgwPf0iG9aRRqccAHXi2/I76tM6UmgR4XTV\nEP988yxcRcoVG5d0L8fejw4BaBLiM8dPp9wvXqCjoRfrsrU4lymklhg4X+ZGCzLHcThz5gyOHDmC\nQCCAEydO4LPPPkO/fv2EFlktDQZHjhxJ25yQDRLMC8JapCtWJ+kBPSPhxfA8L0y/KC0ttaz4yqUc\nwsEwwsHmrcVnTpwFYG7aIVM+3Ca9T07X+Tjhm1ON+PdnJ+ErK4avrBiNZxvg9nrg9koPRHW6XcJN\nTQedVXh3zZCUn8ncODLqnkxb/uqrr/DLX/4SkyZNwsUXX4wXX3xRsnmARq7B4Kuvvkr73GwQj/GG\n36TQ4wWh9NwlS5agZ8+e6NOnD+bMmaN4rHkTActFrOLyMrXCK7c9scWl2R1tQOaNFWLhBQC315Mi\nvHT0e+bEWbRoW2aK+EpFwXL533RRcDQcaxYFO10OIRVR2qoYDWebXNx8ZcUI1Df9n4hwJHj+deNU\n+oI+iSUohxYrRb5i4RVDTICIKdC6detw1VVXYfPmzaipqcGbb74pNHgoYcUFKUI2qiDUpFsySdW8\n//77WLduHfbu3Qun04lvvvlGcT/yVoDlysu0bI9sh/abINUW2TBMTxf1piwaiZornG5XiogAgKdE\nugifRL1GQfK/YvTkg+WiXznkRBhASjQcjzY2ey5wXozF72EuSSe+sVhMSLGFw2FMnz4dw4cPx89+\n9jPYbDaMGTMGLVu2xNy5c4XnqG0wqKioQCwWS9uckA2ykQPW4wWhlKp54YUX8Mgjjwh61KZNG8X9\nyKsUBBHgWCyG+vp6JJNJlJWVaRZferv0NsmY+WxNqyAr8VIr8kqRr7i+V452ndumiG+Lts1L7uTy\nv0oLcNkgGo41+x2digCaRJhAUhIAEPIHhZvNYZf0xQDOi28mTmpGoyS+pOknFArB5/Ph9OnTuOWW\nWzBlyhRhECdBjxWlmudmgwSfMPwmRi4No+YxSqmaQ4cOYcuWLbjiiiswfPhw7NyprCN5FwEHg8GU\nkfB6EW9zzJ27DNjbDPeFcjA731abKsRy4ktHv5FgCL6yEsMjXzWojYLpNITW6FeK+jN1ivfTIhxX\nqJIAMnNS00M68Q2FQuB5HsXFxdizZw9+9rOf4fe//z0GDRrU7PF6Ggzknptt5HK2RpKpF0Q64vE4\nzp07h+3bt+Pjjz/Gbbfdhi+++EL28XkjwKRtMx6PK5aXacXv98Nms2Wloy0dUtEXEWK7s+lPxUsY\nzTjdrpS8Z65Z+89jAICLu0hXX9BUrfsiJZKlSZcLBpqi4NqDx1Mf85+TlFQ5Gh+LieqBzXFSU4uS\n+JKUGMdx8Pl8ePPNN7F06VL885//VEwN6LGilHputjEiBXH62Ic4fewj2fsz9YJIl6qpqKjALbfc\nAgAYMmQIbDYbvv32W7RuLd36nxcCHI/H0djYlMvz+Xy6xZeUrJEefLfbbUnxJRDxlUIqIvaVNW9H\nlUo/mM2Xh79WFOEDB4MAgIazflkRTsfJI6fg+M/7Exd1vdFCzMeapzSA1CsMs1zUpEiX7+V5HsFg\nUGhJXrx4MWpqarB+/fqCaDdWQiploJU2FVegTcUVws//2vZsyv16vCBat24t+9ybb74Z7733Hq69\n9locPHgQ0WhUVnyBPBFgh8OB0tJSQYT1QDui2Wy2ZnPDsk26nKMR4itHJvW/cgtwhLNfp45gURLh\nowdOpX09qSj41LHTkpGrw+loJsJAk7BynE3SJY5AmjPO/2xeFKy20oGYucyaNQtlZWV47bXXDLFk\ntTpSf0OjMStVM3XqVEydOhV9+/aFy+UScu1y5IUXBCkNq6+vh8/ny3hKcSwWg9/vh9vtRlFRUU7H\nBAHaqiDEdcByuWCl6PfrL1Nzrd2/e4nkNtR0wMkhFmCClAiLBVgpCiYiXHsodaFErrY3HosrekXQ\nYqymPtgoQU4nvsSr2uv1orGxEVOnTsVNN92EmTNnWmZqsZlwHIcJD/7b8O2+tvgyS5be5UUErBe6\noy3XC20ELeILpJZL2ex2yfym0+1CoL75VUI0HJF87Bf7pIvsyRe9W7+OkvdnQrp0BJA+FSEWX+B8\na7GYaEj5RMFxNlUlaEZGwmoqHeLxOHw+H44dO4bp06dj7ty5uOGGG1S/Rm1tLSZNmoSvv/4aHMdh\nxqziYN4AABXkSURBVIwZePDBB3H27FncfvvtOHbsGDp37oy//vWvaNHC2BZyo+AtVBpoNnlThkb+\n1XoWE3e0WUF8ASiWnymVoMl1xMlFxGpL1oTXp6Ksg3trhRvh+OGTss+Vi36lUJN+oPny8+Oy99Hv\nV7DBj2CDX/i93PtpNfGl3f5qamowZcoUvPTSS5rEF2hqX160aBH27duH7du34/nnn8f+/fuxYMEC\nVFZW4uDBgxg5ciQWLFig95BMIxtlaFYhbyLgTBzRaG8Ih8OR84U2OcgXvan8KSkrwEaJr1ZRBprE\nmOTmjh8+iYouF2neRqZR8KljTV4PcqV55HeBOvk1AvKcZCKZVfH927JusNvtCIfDcDgcgpkOgaxJ\n2O12eDwe/O1vf8OKFSvw5ptvZjQmvl27dsLMsuLiYvTs2RMnTpzAunXrUF3dNCFi8uTJGD58uGVF\nOC6zYFqI5I0AA+ojYHqhLVtNFXpJXQBqfoxyi3GZiKkRkEhYqxDv23FYaJiQgxZhIr40UiepYEOA\nqqFWWGxLJlLEuPm2jY16iWtZPB5HKBRCIpEQhNhmsyEUCsHtdsPpdOKpp57CoUOHsH79eng80t4W\nWjh69Ch2796NoUOH4vTp04Kgl5eX4/Tp5u+rVUhY2D7SaPIiBUFQI8BksY4M3Mw38W1+X9MlNPG3\nFd/kyESYlRZ55FamiRCrST80ftsAACltw1LUnzmH2oO1kuJLIOIZbAgg2JBqJi/V1Sb1folTFGak\nHDiOE0x0SkpKUFpaCpfLBZ7nEQqFcODAAUyYMAFjx47F8ePHsXLlSkPE1+/3Y8KECXjuueeala3p\nncRsNsRs3sibFGaY8Zw9exaVlZXo1q0bRo0ahbq6NA1CGbw/OSFdCoKMrw8Gg/D5fBg7aW/OqxzU\nIvfFV5xwzNnAcTZEQ5Fmt3gsjpA/KPk8MyLm44dPou7rc4qPIeJLkBPh+jPnt6Pk6wtAMeVAUNte\nnK18L3DeWtLn86Ft27YoKyuDx+PBzp070bVrV92r9bFYDBMmTMDdd9+Nm2++GUBT1HvqVFPe/eTJ\nk2jbNn2TTK7gYzHDb81e4z+GOlVVVfjss8+wevVq7N+/P+UxtBnPsmXLMHPmzLTP1ZprzxsBBuQj\n4Hg8joaGBiHlYJWFNi2IfSHSia8aaE+EkD+ISDAE/7l6+M81j1YziX4JpMoinQiLSRcJA00iLCXE\nZKEt3WQLuS8gjZENGGoqHaLRKIqLi3H48GFMmTIFs2bNwvr16/Gvf/0L+/bt0xWdJpNJTJs2Db16\n9cKsWbOE348bNw4rVqwAAKxYsUIQZivCx3nDb2JoMx6n0ykY6tDImfEoPZd+zuTJk7F27VrFY827\nHHCC+rLl00KbFshiXOrvSCVIGt9glSY6UiJc0kp/WRIR4RZtz49BEke/NESEfWXFKdGvmFgkKkTv\nRHxpaBHmbLa0okswSnzTRb3kCo3jOBQXF2PLli14/PHHsWrVKnTr1k14nN6x8h988AFWrVqFfv36\nYeDAgQCA+fPn4+GHH8Ztt92GP/7xj0IZmlXJhkOdlNHOjh070j5GzoyHPFdrrj1vBFicgsjHhbZ0\nKF0qE0FOIrUemEZJfG0KETWh8WxqvqqkVQvV0a8YKSFWQm00rAY14putqBdIbSt2u91YuXIl/vGP\nf+Ctt95SbFPNhGHDhqUEKTQbN2409LXMYuvaq9M/SCdGmvHQlrbi10j3OnkjwDS0CbvP58ubXK8S\nmdgg0pFCU4QsLcBqxFeKxrN1SPxH+LW0ONPUfX0ubftsWGQk5JCp+IiGUsU+0/rebIovbaDucDjw\n2GOP4dtvv8Wbb74Jt7u5of6FTra61Yw04zl+/Dg6dOgA4HyuvV27dqpy7XmVAwbOf6DzbaEtHUre\nwOkgQiS1+JCp+AIQxBcAAvWNzbrs5KJfAsnfhoOhZiJLkPq9VNQtFl+g6aqATtVYTXzJZBWPx4N4\nPI577rkHrVu3xssvv8zEN8eY5ZusNdeeNxEwqaNMJpOWsI40m+YdcjLTndMIrPiyXW0VRELGH4EW\nYa0VFURsi/4zsUJOlIHzIuxwOiTFl4ZurpB7P4x2Oku32BaJRBCNRuHz+fDNN99g8uTJeOCBB/CD\nH/zA0iVgFwpmmfFozbXnhRkPAME0nfg5cByHGyZ+kuvdyhlqF9vSISeicgJMoE8QLk9Rs/vV5mvT\nQedz5RYg5SJfIsbZjHqJ70gikYDX68W+fftw//33Y/HixbjyyisN2w9GYZA3AhyPxxGJROD3+5FM\nJmGz2cDzPNxuN9xud0EswunBSEHWIr5iXJ4iVeJLi6Lcvst6+P5HiK3k5wCcN1C32WwoKirChg0b\n8PTTT+Mvf/kLLrlE2nlOzNSpU/HWW2+hbdu2+Ne/mqxS586di5deekmYLzZ//nzNHhEMa5I3AvzI\nI49g7969uOKKK3Do0CFMnjwZffv2Bc/zsNlscDgcwo3juIJPUchBUhXpUhNqsEvM2ksnaLQoSj0f\nUI5IbQ67qiqGbFpIAuoqHQKBAFwuF1wuF5YtW4ZNmzbhL3/5iybXsa1bt6K4uBiTJk0SBPjxxx9H\nSUkJHnroIV3HwLAeeZMDnjdvHv7xj39gxowZ6NGjB/7nf/4HPXr0wHXXXYfhw4fD6XQiEokI5T5v\nrOwHh8MBm812wQiykp9EJoIsFkI5MyCCOCIlz6eFOF06gMxrU9pfq4kvmVZcVFQEm82GX/ziF+A4\nDmvXrtU8MPbqq6/G0aNHm/0+T+IkhkbyRoA5jsOZM2ewatUqjBkzBolEAnv37sW7776L6dOnIxgM\n4sorr0RlZSW++93vCpeDZOzQm3/uLwhyIYpxujI2vYKcTCTBJ85XJ4jNgZTSAUSIk4mkoojT26D3\nN90Mt+b7apz4vvZSD+GkTj4/NGRdwuv1IhgMYtq0abj++usxa9YsQxfblixZgpUrV2Lw4MF45pln\nLOvly9BG3qQg0hEMBrF161a888472LFjB1q0aIHrrrsOlZWVqKioEEw5OI4ryHSF3nHqeiJONWIu\ntQ1ajLXkc+WO1Qwns0QiIbiZxeNxId1lt9sRj8cFT4cTJ05gypQpePjhhzF27Fhd4nv06FGMHTtW\nSEF8/fXXQv73V7/6FU6ePIk//vGPhhwnI7cUjADTJJNJnDx5Ehs2bMC7776LQ4cOoXfv3hgxYgRG\njBgBn88nfHnsdjucTmfBpSv0CLLWiFPuuWq30eR9kS6ClzMsSm9BqRW5lEMymQTP84jH44hGo0gm\nk/jNb36DcDiMrVu3Yvny5bjqqqt0v75YgNXex8g/ClKAxdDpik2bNjVLVwBNVRYkXUFfbhaCGAOZ\nCXK6iNMIsimsalBT6RAIBIRpxX/4wx+wdu1axGIx7Nu3D4sXL8bUqVN17YNYZE+ePImLLmryXV60\naBE+/vhjvPLKK7peg2ENLggBFiOXrrj++uvRsWNH4bLzQk5XpBPGTJ4vfm62xTUdWtuKn3vuOeza\ntQsrV65EcXEx/H4/YrEYWrZU538hxcSJE1FdXY0zZ86gvLwcjz/+ODZv3ow9e/aA4zhccskl+MMf\n/pDRtAyG9bggBZhGa7rC4XAI+WSrDPjUi55x7FKCbDVhVYPaacUejwfJZBKzZs3Cd77zHTz11FMX\nxKh4hjlc8AIsRild0aJFCwQCAXTv3r1ZdExWxwshQs6UJhvN/BJfNZ1tdFtxfX09pkyZgltvvRUz\nZsxgbcUMXTABTkMwGMSWLVuwcOFC7NixA2PGjMGVV16J66+/HhdffLGwKFOo6YpCRmtb8ZEjRzB9\n+nT8+te/xqhRo7K0l4xCJm/qgHOF1+tFixYtUF9fj927d6O4uBgbNmzAwoULm6Ur6GYQu92OdSv6\npkzCZYJsHdS2FXMcB5/Phw8//BCPPvoo/vSnP6F3795Z2ktGoWPpCLiqqgqzZs0Cz/OYPn065syZ\nk7N9ITlgGpKueOedd/Dee+9pqq4ALux0RS5Ra6DudDrhcrmwZs0arFq1CmvWrLH0LDVG/mFZAeZ5\nHt27d8fGjRvRoUMHDBkyBKtXrxZs36yIUnUFS1dYA7WVDkVFRXA4HJg3bx6OHj2Kl19+GUVFzV3f\nGAw9WFaAP/roIzz++OOoqqoCAGG66MMPP5zL3VJNJtUVLF1hLmorHbxeL2KxGO677z5069YNc+fO\nbdaCLIeUm9nZs2dx++2349ixY4JHLGslZgAWFuC///3veOedd/Diiy8CAFatWoUdO3ZgyZIlOd6z\nzJBLV1x//fUYNGgQAJauMAs1i23hcBjxeBxerxfffvstpkyZgqlTp+KHP/yhpkoHKTez2bNn4zvf\n+Q5mz56Np556CufOnUs7rpxxYWDZRbhCK++x2WwYMGAABgwYgDlz5gjpiqqqKjz++OPN0hXxeBzh\ncFhIV7y1agAcDgfi8Ti+98M9uT6cvEGN+BLTJp/Ph88//xw//vGP8dvf/hbXXnut5teTcjNbt24d\nqqurATSNKh8+fDgTYAYACwuwmqF5+YzX68Xo0aMxevTolHSFUnUFGWu+9k+94XK5WLoiDW+tGiA7\nsRY431Zst9vh9Xrx/vvv48knn8Qrr7yCrl27GrYfWkeVMy4cLJuCiMfj6N69OzZt2oT27dvj8ssv\nt/winFGI0xX19fWIxWLo3r07Fi9eDI7jhHSF2EwIYOkKAFi3oq9ijl1soL58+XK88cYbWL16NVq1\naqXrtcVeDi1btsS5c+eE+1u1aoWzZ8/qeg1GYWDZCFhp8F2hQ6crxo8fj9GjR2PQoEEoLy/HuHHj\n0LJlS1Xpigs1OqbTDslkUrCSJE0VNpsNiUQCZ86cwcUXX4xf/epXqK+vxxtvvAGXS9ugUTVoHVXO\nuHCwbAScazp37ozS0lIhwqypqcnJfjQ2NmLz5s0YO3YsAHXVFaTc7UKrrlDbVhyJRGC32zFy5Eic\nOHECnTp1wgMPPICxY8cKvrt6EEfAs2fPRuvWrTFnzhwsWLAAdXV1LAfMAMAEWJZLLrkEn3zyie7L\nUbNRW12RSCQEMXY6nQWXrlDbVkxMlE6fPo177rkHEydOhMPhwKZNmzBz5kwMHz5c136I3cyeeOIJ\n3HTTTbjtttvw5ZdfsjI0RgpMgGW45JJLsHPnTrRu3TrXu6IJuhlk+/btzdIVhdgMokZ8yQKm1+vF\n3r178eCDD2Lp0qUYOnRolvaSwWgOE2AZLr30UpSVlcFut+Pee+/Fj370o1zvkmYuhHSF2rZih8MB\nt9uN9evXY9GiRVi9ejU6deqUpb1kMKRhAiwDmULwzTffoLKyEkuWLMHVV1+d693SRSbpCiuPatJi\noO5yufDCCy+guroaq1atQllZWZb2ksGQhwmwCh5//HEUFxfjv//7v3O9K4aiNl0BQMgbh8NhuN1u\nuN1ujL5jZ072O53wAqkG6kDTQpjL5cKiRYvgcFi2+IdxgcEEWIJgMAie51FSUoJAIIBRo0bhscce\nK2gP2HTpisOHD6NTp07weDw5TVdoNVD3+/2YNm0abrjhBjzwwAMF12HJyG+YAEtw5MgRjB8/HkDT\nZexdd92FRx55JMd7lV1IumL9+vV48cUX4ff7cdddd2HMmDEYNGgQOI5DLBbLarpCS1ux1+tFbW0t\npk6dikcffRTf//73Dd8fBkMvTIAZisybNw8bNmzA8uXLceDAgWbpipEjR6JTp04p6QpS6ma32w0r\nd1NroG6z2eDxeLBz5078/Oc/x0svvYT+/fvrem0GwyyYAFsAK1sY+v1+uN1uOJ1O4XfJZBJfffUV\nNmzYgA0bNuDQoUPo1asXrrvuOlOqK9RUOtBtxWvXrsWyZcvw6quvon379hkdN2CdZhxG4cIE2ALk\nu4UhXV2xadMmhEKhlOoK4l3B87zmdEU68Y3FYgiFQoKB+rPPPou9e/di5cqV8Hq9uo4rX5pxGPkL\nE2CLIG5f7dGjB6qrqwUfgeHDh+PAgQM53kt1yFVXyKUrpLyP1eR7o9EoIpEIvF4veJ7HT3/6U1x0\n0UWYN2+eIaPi87UZh5E/MAG2CEoOWslkEq1atUpx1MoX9KYr5LZJDNR9Ph/q6upwzz334I477sC0\nadMMq3QohGYchrVhBZF5AMdxeVs+xXEcOnTogHvuuQf33HNPSrpi2rRpzdIVABAOh2XTFaTSAQCK\ni4tx+PBhzJgxA08++SSuv/56Q/f9gw8+SGnG6dGjR9434zCsBRNgi1KoFoZKk0Hmzp0rma6IRCIA\nALvdDp7nkUwmUVpaim3btuFXv/oVVqxYYYpV6UUXXQQAaNOmDcaPH4+amhomwAxDYQJsUcaNG4cV\nK1Zgzpw5WLFiBW6++eZc75IpiCeDkHTFwoULcfjwYSFdQSZJjB49GpMmTcLx48cRDAaxaNEiXHrp\npYbvl7gZ591338Vjjz1m+OswLmxYDtgCMAtDaUi6YuHChVi7di1GjhyJHj164NSpU4hEIujSpQve\ne+89XHPNNVi4cKGhr82acRjZgAkww9KcPn0aI0aMwKuvvoouXbpg06ZNeP3117Fs2TKhakJp7huD\nYWWYADMkG0Hmzp2Ll156SZgQMX/+fNxwww052T8y143BKDRsud4BRu6ZMmUKqqqqUn7HcRweeugh\n7N69G7t3786Z+AJg4ssoWJgAM3D11VejZcuWzX7PLo4YDHNhAsyQZcmSJejfvz+mTZuGurq6XO8O\ng1FwMAFmSDJz5kwcOXIEe/bswUUXXVRwZvQMhhVgAsyQpG3btkIH3vTp05kTGINhAkyAGZKcPHlS\n+P8///lP9O3bN4d7w2AUJkyAGZg4cSKuuuoqfP755+jYsSNefvllzJkzB/369UP//v1RXV2NRYsW\n5Xo3VVNVVYUePXqga9eueOqpp3K9OwyGLKwOmFFQ8DyP7t27Y+PGjejQoQOGDBmC1atXm+IVwWDo\nhUXAjJxTW1uLESNGoHfv3ujTpw8WL14MoGkqSGVlJbp164ZRo0apqsSoqalBly5d0LlzZzidTtxx\nxx14/fXXzT4EBiMjmAAzco7T6cSiRYuwb98+bN++Hc8//zz279+PBQsWoLKyEgcPHsTIkSNVTQQ5\nceIEOnbsKPxcUVGBEydOmLn7DEbGMAFm5Jx27dphwIABAJo8fnv27IkTJ05g3bp1mDx5MgBg8uTJ\nWLt2bdptMU8IRj7BBJhhKY4ePYrdu3dj6NChOH36NMrLywFAsKNMR4cOHVBbWyv8XFtbi4qKCtP2\nl8HQAxNghmXw+/2YMGECnnvuOZSUlKTcp3YqyODBg3Ho0CEcPXoU0WgUa9aswbhx48zaZQZDF8yQ\nnWEJYrEYJkyYgLvvvlswn89kKojD4cDSpUsxevRo8DyPadOmsQoIhmVhZWiMnJNMJjF58mS0bt06\npd549uzZaN26NebMmYMFCxagrq5O1UIcg5EvMAFm5Jxt27bhmmuuQb9+/YQ0w/z583H55Zdf8FNB\nGIUNE2AGg8HIEWwRjsFgMHIEE2AGg8HIEf8fpJ/eyQ1DdDYAAAAASUVORK5CYII=\n", - "text": [ - "" - ] - } - ], - "prompt_number": 11 - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "function: cython_pdf_opt , av. time sec: 0.00002623, min. time sec: 0.00002379, relative: 1.0\n", + "function: cython_pdf_unrolled , av. time sec: 0.00004890, min. time sec: 0.00004316, relative: 1.9\n", + "function: native_pdf , av. time sec: 0.00005467, min. time sec: 0.00004636, relative: 2.1\n", + "function: hope_pdf , av. time sec: 0.00013511, min. time sec: 0.00010329, relative: 5.2\n", + "function: numba_pdf , av. time sec: 0.00018622, min. time sec: 0.00017234, relative: 7.1\n", + "function: cython_pdf , av. time sec: 0.00461271, min. time sec: 0.00386866, relative: 175.9\n", + "function: pdf , av. time sec: 0.00688719, min. time sec: 0.00635740, relative: 262.6\n" + ] + } + ], + "source": [ + "funcs = [\"pdf\", \n", + " \"numba_pdf\", \n", + " \"hope_pdf\", \n", + " \"cython_pdf\", \n", + " \"cython_pdf_opt\", \n", + " \"cython_pdf_unrolled\",\n", + " \"native_pdf\", \n", + " ]\n", + "perf_comp_data(funcs, \n", + " len(funcs)*[\"density, dims, center, w2D, r50, b, a\"], rep=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, "metadata": {}, - "outputs": [], - "prompt_number": 9 + "output_type": "display_data" } ], - "metadata": {} + "source": [ + "from matplotlib import pyplot as plt\n", + "from mpl_toolkits.mplot3d import Axes3D\n", + "from matplotlib import cm\n", + "from matplotlib.ticker import LinearLocator, FormatStrFormatter\n", + "\n", + "density = np.zeros((dims[0], dims[1]), dtype=np.float32)\n", + "pdf(density, dims, center, w2D, r50, b, a)\n", + "\n", + "fig = plt.figure()\n", + "ax = fig.gca(projection='3d')\n", + "gx, gy = np.mgrid[0:dims[0], 0:dims[1]]\n", + "surf = ax.plot_surface(gx, gy, density, rstride=1, cstride=1, cmap=cm.coolwarm, linewidth=0, antialiased=False)\n", + "fig.colorbar(surf, shrink=0.5, aspect=5)\n", + "plt.show()" + ] } - ] -} \ No newline at end of file + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/docs/Makefile b/docs/Makefile index 1005e26..f5036a4 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -50,6 +50,11 @@ clean: rm -rf $(BUILDDIR)/* html: + @echo copy html versions of benchark notebooks to $(BUILDDIR)/html/benchmarks + mkdir -p $(BUILDDIR) + mkdir -p $(BUILDDIR)/html + mkdir -p $(BUILDDIR)/html/benchmarks + cp ../benchmarks/*.html $(BUILDDIR)/html/benchmarks $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." @@ -174,4 +179,4 @@ xml: pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." \ No newline at end of file + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/conf.py b/docs/conf.py index 6d7e79c..6aae040 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -253,9 +253,6 @@ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False -try: - import sphinx_eth_theme - html_theme = "sphinx_eth_theme" - html_theme_path = [sphinx_eth_theme.get_html_theme_path()] -except ImportError: - html_theme = 'default' \ No newline at end of file +import sphinx_pynpoint_theme +html_theme = "sphinx_pynpoint_theme" +html_theme_path = [sphinx_pynpoint_theme.get_html_theme_path()] diff --git a/docs/index.rst b/docs/index.rst index 2815ed2..f1c424c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,7 +21,10 @@ Contents Benchmarks ---------- -All the benchmarks have been made available online as `IPython notebooks `_ (also on `GitHub `_). If you would like to run the benchmarks on your machine, you can download the notebooks in the nbviewer. +All the benchmarks have been made available online as `IPython notebooks +`_. -**Note**: Make sure to execute the *native_cpp_gen* the first time in order to generate the native C++ code and some Python utility modules. +Test coverage +------------- +`Test coverage reports `_. diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..97e16d1 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,2 @@ +hope_calls +hope_numpy diff --git a/examples/hope_numpy.py b/examples/hope_numpy.py index 1cce654..3e6b2c1 100644 --- a/examples/hope_numpy.py +++ b/examples/hope_numpy.py @@ -69,4 +69,4 @@ def example(): assert np.all(r == [1.25, 1.5, 1.75]) if __name__ == '__main__': - example() \ No newline at end of file + example() diff --git a/hope/__init__.py b/hope/__init__.py index e8aca8a..dd85445 100644 --- a/hope/__init__.py +++ b/hope/__init__.py @@ -17,7 +17,7 @@ __all__ = ["jit", "config", "serialize", "unserialize"] __author__ = "Lukas Gamper, Joel Akeret" __email__ = "hope@phys.ethz.ch" -__version__ = "0.6.1" +__version__ = "0.7.0" __credits__ = "ETH Zurich, Institute for Astronomy" from hope import config diff --git a/hope/_ast.py b/hope/_ast.py index 5088f08..952dc27 100644 --- a/hope/_ast.py +++ b/hope/_ast.py @@ -7,6 +7,7 @@ from __future__ import print_function, division, absolute_import, unicode_literals +import ast import copy from hope._const import * @@ -390,3 +391,22 @@ def visit(self, node): def generic_visit(self, node): raise Exception("Not Implemented Token: {0}({1!s})".format(type(node).__name__, node)) + + +def call_has_kw_args(node): + if hasattr(node, "kwargs"): + return node.kwargs is not None + return any(kw.arg is None for kw in getattr(node, "keywords", [])) + + +def call_has_starargs(node): + if hasattr(node, "starargs"): + return node.starargs is not None + try: + # must be defined in Python 3 + ast.Starred + except AttributeError: + raise RuntimeError("should not happen") + return any(isinstance(arg, ast.Starred) for arg in node.args) + + diff --git a/hope/_tosource.py b/hope/_tosource.py index f644a4a..3d48cc4 100644 --- a/hope/_tosource.py +++ b/hope/_tosource.py @@ -232,11 +232,11 @@ def paren_or_comma(): paren_or_comma() self.write(keyword.arg + '=') self.visit(keyword.value) - if node.starargs is not None: + if getattr(node, "starargs", None) is not None: paren_or_comma() self.write('*') self.visit(node.starargs) - if node.kwargs is not None: + if getattr(node, "kwargs", None) is not None: paren_or_comma() self.write('**') self.visit(node.kwargs) @@ -436,13 +436,17 @@ def write_comma(): self.visit(arg) for keyword in node.keywords: write_comma() - self.write(keyword.arg + '=') - self.visit(keyword.value) - if node.starargs is not None: + if keyword.arg is not None: + self.write(keyword.arg + '=') + self.visit(keyword.value) + else: + self.write("**") + self.visit(keyword.value) + if getattr(node, "starargs", None) is not None: write_comma() self.write('*') self.visit(node.starargs) - if node.kwargs is not None: + if getattr(node, "kwargs", None) is not None: write_comma() self.write('**') self.visit(node.kwargs) @@ -628,4 +632,4 @@ def visit_arguments(self, node): self.signature(node) def visit_arg(self, node): - self.write(node.arg) \ No newline at end of file + self.write(node.arg) diff --git a/hope/_transformer.py b/hope/_transformer.py index cd5d746..7efb962 100644 --- a/hope/_transformer.py +++ b/hope/_transformer.py @@ -179,6 +179,8 @@ def visit_Num(self, node): return True def visit_Name(self, node): return True + def visit_NameConstant(self, node): + return True def visit_Slice(self, node): return node.lower if node.lower is None else self.visit(node.lower) and node.upper if node.upper is None else self.visit(node.upper) def visit_ExtSlice(self, node): @@ -428,7 +430,7 @@ def visit_For(self, node): raise Exception("The variable '{0}' does already exists, since the scopeing is different in c++ and python, this is not supported".format(iter.name)) # TODO: implement this more generic if isinstance(node.iter, ast.Call) and isinstance(node.iter.func, ast.Name) and node.iter.func.id in ["range", "xrange"] \ - and len(node.iter.keywords) == 0 and node.iter.starargs is None and node.iter.kwargs is None: + and not call_has_kw_args(node.iter): if len(node.iter.args) == 1: args = [Number(0), self.visit(node.iter.args[0])] elif len(node.iter.args) == 2: @@ -575,7 +577,10 @@ def visit_Call(self, node): return self.variables[name] elif isinstance(node.func, ast.Attribute): - if not node.starargs is None or not node.kwargs is None: + + if call_has_starargs(node): + raise UnsupportedFeatureException("Only arguments without default values are supported in calls") + if call_has_kw_args(node): raise UnsupportedFeatureException("Only arguments without default values are supported in calls") return Call(self.visit(node.func), diff --git a/hope/_wrapper.py b/hope/_wrapper.py index bdb23dd..dfad428 100644 --- a/hope/_wrapper.py +++ b/hope/_wrapper.py @@ -271,8 +271,8 @@ def _compile(target, localfilename, fkt_name): try: #trying to encode utf-8 to support AstroPy warnings.warn("A warning has been issued during compilation:\n{0}".format(out).encode('utf-8')) - except UnicodeError: - #encoding fails on Linux + except (UnicodeError, TypeError): + #encoding fails on Linux and Python 3 warnings.warn("A warning has been issued during compilation:\n{0}".format(out)) if config.verbose: diff --git a/hope/options.py b/hope/options.py index 0c8758c..df039b3 100644 --- a/hope/options.py +++ b/hope/options.py @@ -6,10 +6,12 @@ from hope.exceptions import UnsupportedCompilerException CXX_FLAGS = { - "clang": ["-Wall", "-Wno-unused-variable", "-march=native", "-stdlib=libc++", "-std=c++11"], - "icc": ["-Wall", "-Wno-unused-variable", "-march=native", "-stdlib=libc++", "-std=c++11"], - "gcc-mac": ["-Wall", "-Wno-unused-variable", "-std=c++11", "-msse4.2"], - "gcc-linux": ["-Wall", "-Wno-unused-variable", "-std=c++11"] + "clang": ["-Wall", "-Wno-unused-variable", "-march=native", "-stdlib=libc++", "-std=c++11", + "-Wno-unreachable-code"], + "icc": ["-Wall", "-Wno-unused-variable", "-march=native", "-stdlib=libc++", "-std=c++11", + "-Wno-unreachable-code"], + "gcc-mac": ["-Wall", "-Wno-unused-variable", "-std=c++11", "-msse4.2", "-Wno-unreachable-code"], + "gcc-linux": ["-Wall", "-Wno-unused-variable", "-std=c++11", "-Wno-unreachable-code"] } DARWIN_KEY = "Darwin" diff --git a/render_benchmarks_to_html.sh b/render_benchmarks_to_html.sh new file mode 100755 index 0000000..59831df --- /dev/null +++ b/render_benchmarks_to_html.sh @@ -0,0 +1,27 @@ +#!/bin/bash + + +function convert +{ + jupyter nbconvert --log-level=10 --to html --execute --ExecutePreprocessor.timeout=-1 "$1" +} + +pushd benchmarks + +rm -f *.so +rm -f src/*.o +rm -rf .hope +rm -rf hope + +set -e + +convert native_cpp_gen.ipynb +convert "HPC Python.ipynb" +convert fibonacci.ipynb +convert simplify.ipynb +convert star.ipynb +convert julialang.org.ipynb +convert numexpr.ipynb +convert pairwise.ipynb + +popd diff --git a/requirements.txt b/requirements.txt index e0dc245..cb80763 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ +--extra-index-url https://cosmo-pypi.phys.ethz.ch/simple/ Sphinx>=1.2.3 coverage>=3.7.1 flake8>=2.2.4 @@ -6,4 +7,13 @@ numpy>=1.9.2 pytest>=2.6.3 pytest-cov>=1.8.0 sympy>=0.7.5 -tox==1.8.0 +matplotlib +Cython + +# only needed for createing docs with Python 3 +scipy; python_version >= '3' +jupyter; python_version >= '3' +numba; python_version >= '3' +numexpr; python_version >= '3' +version_information; python_version >= '3' +sphinx-pynpoint-theme; python_version >= '3' diff --git a/setup.py b/setup.py index b717c08..ff1ffb0 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ def run_tests(self): setup( name="hope", - version="0.6.1", + version="0.7.0", description="A Python Just-In-Time compiler for astrophysical computations", long_description=readme + "\n\n" + history, author="Lukas Gamper, Joel Akeret", @@ -66,6 +66,8 @@ def run_tests(self): "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Mathematics", "Topic :: Scientific/Engineering :: Physics", diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000..baeebd5 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,11 @@ +# encoding: utf-8 +from __future__ import print_function, division, absolute_import + +# we set a seed, because the legacy hope test code uses random data in somep places which caused +# unforeseeable failures when numpy changed its behaviour handling exponentiation of integer +# types. +import random +import numpy as np + +random.seed(12345) +np.random.seed(12345) diff --git a/test/test_blocks.py b/test/test_blocks.py index a57d280..972acbf 100644 --- a/test/test_blocks.py +++ b/test/test_blocks.py @@ -9,7 +9,7 @@ import itertools import pytest -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype", dtypes) def test_blocks_1(dtype): diff --git a/test/test_call.py b/test/test_call.py index 5f859a5..ab9a25f 100644 --- a/test/test_call.py +++ b/test/test_call.py @@ -9,7 +9,7 @@ import itertools import pytest -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module def fkt_call_local_fun_callback(a, b): a[:] = b @@ -117,4 +117,4 @@ def test_recursion(): hope_fkt_recursion_callback = hope.jit(fkt_recursion_callback) assert hope_fkt_recursion_callback(20) == 6765 -# TODO: make tests for function calls with return types and expr / local vars as arguments \ No newline at end of file +# TODO: make tests for function calls with return types and expr / local vars as arguments diff --git a/test/test_cast.py b/test/test_cast.py index c070b06..cd4955e 100644 --- a/test/test_cast.py +++ b/test/test_cast.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype", [dtype for dtype in dtypes if dtype != float]) def test_func_bool_(dtype): diff --git a/test/test_comparison.py b/test/test_comparison.py index 458366e..00e92b3 100644 --- a/test/test_comparison.py +++ b/test/test_comparison.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes[1:])) @make_test diff --git a/test/test_control_structures.py b/test/test_control_structures.py index 3fda07a..ede549c 100644 --- a/test/test_control_structures.py +++ b/test/test_control_structures.py @@ -6,9 +6,16 @@ from __future__ import print_function, division, absolute_import, unicode_literals import numpy as np -import hope, itertools, pytest, sys, sysconfig, os, shutil +import hope +import itertools +import pytest +import sys +import sysconfig +import os +import shutil + +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module def test_ifelse_scalar(): def fkt(a, b, c): @@ -30,6 +37,7 @@ def fkt(a, b, c): # for aa in a: # c[0] = a + @pytest.mark.parametrize("dtype", dtypes) def test_for_range_1(dtype): def fkt(a, b, c): @@ -37,14 +45,17 @@ def fkt(a, b, c): c[:, i] = a[i, :] c[i, 1] = a[0, 1] + b[i, 5] hfkt = hope.jit(fkt) - (ao, ah), (bo, bh), (co, ch) = random(dtype, [10, 10]), random(dtype, [10, 10]), random(dtype, [10, 10]) - ao, ah, bo, bh = (ao / 2.).astype(dtype), (ah / 2.).astype(dtype), (bo / 2.).astype(dtype), (bh / 2.).astype(dtype) + (ao, ah), (bo, bh), (co, ch) = random(dtype, [10, 10]), random( + dtype, [10, 10]), random(dtype, [10, 10]) + ao, ah, bo, bh = (ao / 2.).astype(dtype), (ah / 2.).astype(dtype), (bo / + 2.).astype(dtype), (bh / 2.).astype(dtype) ro, rh = fkt(ao, bo, co), hfkt(ah, bh, ch) assert check(co, ch) ro, rh = fkt(ao, bo, co), hfkt(ah, bh, ch) assert check(co, ch) -@pytest.mark.skipif("sys.version_info[0] > 2") + +@pytest.mark.skipif(sys.version_info.major >= 3, reason="requires python2") @pytest.mark.parametrize("dtype", dtypes) def test_for_xrange_1(dtype): def fkt(a, b, c): @@ -52,13 +63,16 @@ def fkt(a, b, c): c[:, i] = a[i, :] c[i, 1] = a[0, 1] + b[i, 5] hfkt = hope.jit(fkt) - (ao, ah), (bo, bh), (co, ch) = random(dtype, [10, 10]), random(dtype, [10, 10]), random(dtype, [10, 10]) - ao, ah, bo, bh = (ao / 2.).astype(dtype), (ah / 2.).astype(dtype), (bo / 2.).astype(dtype), (bh / 2.).astype(dtype) + (ao, ah), (bo, bh), (co, ch) = random(dtype, [10, 10]), random( + dtype, [10, 10]), random(dtype, [10, 10]) + ao, ah, bo, bh = (ao / 2.).astype(dtype), (ah / 2.).astype(dtype), (bo / + 2.).astype(dtype), (bh / 2.).astype(dtype) ro, rh = fkt(ao, bo, co), hfkt(ah, bh, ch) assert check(co, ch) ro, rh = fkt(ao, bo, co), hfkt(ah, bh, ch) assert check(co, ch) + @pytest.mark.parametrize("dtype", dtypes) def test_for_range_2(dtype): def fkt(a, b, c): @@ -66,12 +80,15 @@ def fkt(a, b, c): c[:, i] = a[i, :] c[i, 1] = a[0, 1] + b[i, 5] hfkt = hope.jit(fkt) - (ao, ah), (bo, bh), (co, ch) = random(dtype, [10, 10]), random(dtype, [10, 10]), random(dtype, [10, 10]) - ao, ah, bo, bh = (ao / 2.).astype(dtype), (ah / 2.).astype(dtype), (bo / 2.).astype(dtype), (bh / 2.).astype(dtype) + (ao, ah), (bo, bh), (co, ch) = random(dtype, [10, 10]), random( + dtype, [10, 10]), random(dtype, [10, 10]) + ao, ah, bo, bh = (ao / 2.).astype(dtype), (ah / 2.).astype(dtype), (bo / + 2.).astype(dtype), (bh / 2.).astype(dtype) assert check(co, ch) ro, rh = fkt(ao, bo, co), hfkt(ah, bh, ch) assert check(co, ch) + @pytest.mark.parametrize("dtype", dtypes) def test_for_iteration_vars(dtype): """ @@ -82,18 +99,18 @@ def fkt(a, b, size_x): n = 2 for dx in range(2 * n + 1): b[n + 1:(size_x - n - 1)] += a[dx + 1:(size_x + dx - 2 * n - 1)] - + hfkt = hope.jit(fkt) size_x = 10 ao, ah = random(dtype, [size_x]) ao = (ao / (2 * size_x + 1)).astype(dtype) ah = (ah / (2 * size_x + 1)).astype(dtype) - + bo, bh = np.zeros((size_x), dtype), np.zeros((size_x), dtype) - + fkt(ao, bo, size_x) hfkt(ah, bh, size_x) - + assert check(bo, bh) @@ -109,4 +126,22 @@ def fkt(): ro, rh = fkt(), hfkt() assert check(ro, rh) + +def test_if_const(): + def fkt(): + if True: + a = 1 + else: + a = 2 + if False: + b = 7 + else: + b = 2 + return a + b + + hfkt = hope.jit(fkt) + ro, rh = fkt(), hfkt() + assert check(ro, rh) + + # TODO: make test for for/wile with array and for/else wihle/else diff --git a/test/test_dump.py b/test/test_dump.py index 762322f..5a8d485 100644 --- a/test/test_dump.py +++ b/test/test_dump.py @@ -55,4 +55,4 @@ def test_dump_complex(self): assert fkt_str is not None - \ No newline at end of file + diff --git a/test/test_functions.py b/test/test_functions.py index 2865ab7..a834827 100644 --- a/test/test_functions.py +++ b/test/test_functions.py @@ -10,7 +10,7 @@ import pytest import copy -from test.utilities import random, check, make_test, dtypes, shapes +from .utilities import random, check, make_test, dtypes, shapes import hope from hope.exceptions import UnsupportedFeatureException diff --git a/test/test_object.py b/test/test_object.py index 0bf992e..e33f848 100644 --- a/test/test_object.py +++ b/test/test_object.py @@ -8,7 +8,7 @@ import hope import numpy as np -from test.utilities import check,setup_module,setup_method,teardown_module +from .utilities import check,setup_module,setup_method,teardown_module class SubCls(object): @@ -148,4 +148,4 @@ def fkt(self): t1 = Test() a = t1.fkt() ah = t1.hfkt() - assert np.all(a==ah) \ No newline at end of file + assert np.all(a==ah) diff --git a/test/test_op_binary.py b/test/test_op_binary.py index f88eb88..c247ec9 100644 --- a/test/test_op_binary.py +++ b/test/test_op_binary.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product([dtype for dtype in dtypes if issubclass(dtype, np.integer) or dtype == int], shapes)) @make_test diff --git a/test/test_op_bool.py b/test/test_op_bool.py index a2723f2..e5288f4 100644 --- a/test/test_op_bool.py +++ b/test/test_op_bool.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", [[np.int8, []]]) @make_test diff --git a/test/test_op_div.py b/test/test_op_div.py index 318dc7f..2e92823 100644 --- a/test/test_op_div.py +++ b/test/test_op_div.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes[1:])) def test_binary_div(dtype, shape): @@ -16,8 +16,8 @@ def fkt(a, b, c): c[:] = a / b hfkt = hope.jit(fkt) (ao, ah), (bo, bh), (co, ch) = random(dtype, shape), random(dtype, shape), random(dtype, shape) - if np.count_nonzero(bo == 0) > 0: bo[bo == 0] += 1 - if np.count_nonzero(bh == 0) > 0: bh[bh == 0] += 1 + bo[bo == 0] += 1 + bh[bh == 0] += 1 ro, rh = fkt(ao, bo, co), hfkt(ah, bh, ch) if dtype in [np.float32, np.float64, float]: co[co < 1. / (np.finfo(dtype).max * np.finfo(dtype).resolution)] /= np.finfo(dtype).resolution @@ -30,8 +30,8 @@ def fkt(a, b, c): c[:] = a // b hfkt = hope.jit(fkt) (ao, ah), (bo, bh), (co, ch) = random(dtype, shape), random(dtype, shape), random(dtype, shape) - if np.count_nonzero(bo == 0) > 0: bo[bo == 0] += 1 - if np.count_nonzero(bh == 0) > 0: bh[bh == 0] += 1 + bo[bo == 0] += 1 + bh[bh == 0] += 1 ro, rh = fkt(ao, bo, co), hfkt(ah, bh, ch) if dtype in [np.float32, np.float64, float]: co[co < 1. / (np.finfo(dtype).max * np.finfo(dtype).resolution)] /= np.finfo(dtype).resolution @@ -50,8 +50,8 @@ def fkt(a, b, c): ao, ah, bo, bh = ao.astype(np.float64), ah.astype(np.float64), bo.astype(np.float64), bh.astype(np.float64) ao, ah = np.copysign(np.power(np.abs(ao), 1. / 4.), ao).astype(dtypea), np.copysign(np.power(np.abs(ah), 1. / 4.), ah).astype(dtypea) bo, bh = np.copysign(np.power(np.abs(bo), 1. / 4.), bo).astype(dtypeb), np.copysign(np.power(np.abs(bh), 1. / 4.), bh).astype(dtypeb) - if np.count_nonzero(bo == 0) > 0: bo[bo == 0] += 1 - if np.count_nonzero(bh == 0) > 0: bh[bh == 0] += 1 + bo[bo == 0] += 1 + bh[bh == 0] += 1 fkt(ao, bo, co), hfkt(ah, bh, ch) assert check(co, ch) fkt(ao, bo, co), hfkt(ah, bh, ch) @@ -66,8 +66,8 @@ def fkt(a, c): (ao, ah) = random(dtype, shape) (co, ch) = random(np.float64, shape) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + ao[ao == 0] += 1 + ah[ah == 0] += 1 ro, rh = fkt(ao, co), hfkt(ah, ch) if dtype in [np.float32, np.float64, float]: @@ -81,8 +81,8 @@ def fkt(a, c): c[:] //= a hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, shape), random(dtype, shape) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + ao[ao == 0] += 1 + ah[ah == 0] += 1 ro, rh = fkt(ao, co), hfkt(ah, ch) if dtype in [np.float32, np.float64, float]: co[co < 1. / (np.finfo(dtype).max * np.finfo(dtype).resolution)] /= np.finfo(dtype).resolution diff --git a/test/test_op_minus.py b/test/test_op_minus.py index aa11e84..504b0dd 100644 --- a/test/test_op_minus.py +++ b/test/test_op_minus.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes[1:])) @make_test diff --git a/test/test_op_mult.py b/test/test_op_mult.py index 668a6a6..2476ff2 100644 --- a/test/test_op_mult.py +++ b/test/test_op_mult.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes[1:])) def test_binary_mult(dtype, shape): diff --git a/test/test_op_plus.py b/test/test_op_plus.py index 5a0eabb..63dd0d2 100644 --- a/test/test_op_plus.py +++ b/test/test_op_plus.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes[1:])) @make_test diff --git a/test/test_op_pow.py b/test/test_op_pow.py index 434e3df..fea71b4 100644 --- a/test/test_op_pow.py +++ b/test/test_op_pow.py @@ -8,21 +8,21 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes[1:])) def test_augmented_pow(dtype, shape): - def fkt(a, c): + def fkt(a, c): c[:] **= a hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(np.uint8, shape), random(dtype, shape) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 - if np.count_nonzero(co == 0) > 0: co[co == 0] += 1 - if np.count_nonzero(ch == 0) > 0: ch[ch == 0] += 1 + ao[ao == 0] += 1 + ah[ah == 0] += 1 + co[co == 0] += 1 + ch[ch == 0] += 1 co, ch = np.copysign(np.sqrt(np.abs(co)), co).astype(dtype), np.copysign(np.sqrt(np.abs(ch)), ch).astype(dtype) ao, ah = np.power(np.abs(ao).astype(np.float64), 1. / co.astype(np.float64)).astype(dtype), np.power(np.abs(ah).astype(np.float64), 1. / ch.astype(np.float64)).astype(dtype) - fkt(ao, co), hfkt(ah, ch) + fkt(np.abs(ao), co), hfkt(np.abs(ah), ch) assert check(co, ch) # TODO: fix for np.ulonglong and uint64, std::power produce different results diff --git a/test/test_operators.py b/test/test_operators.py index 5e78fd6..2e86d3c 100644 --- a/test/test_operators.py +++ b/test/test_operators.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype,shape", itertools.product([dtype for dtype in dtypes if issubclass(dtype, np.integer) or dtype == int], shapes[1:])) def test_binary_mod(dtype, shape): @@ -18,8 +18,8 @@ def fkt(a, b, c): c[:] = a % b hfkt = hope.jit(fkt) (ao, ah), (bo, bh), (co, ch) = random(dtype, shape), random(dtype, shape), random(dtype, shape) - if np.count_nonzero(bo == 0) > 0: bo[bo == 0] += 1 - if np.count_nonzero(bh == 0) > 0: bh[bh == 0] += 1 + bo[bo == 0] += 1 + bh[bh == 0] += 1 fkt(ao, bo, co), hfkt(ah, bh, ch) assert check(co, ch) fkt(ao, bo, co), hfkt(ah, bh, ch) @@ -55,8 +55,8 @@ def fkt(a, c): c[:] %= a hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, shape), random(dtype, shape) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + ao[ao == 0] += 1 + ah[ah == 0] += 1 fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) diff --git a/test/test_optimize.py b/test/test_optimize.py index 83d25d1..6643113 100644 --- a/test/test_optimize.py +++ b/test/test_optimize.py @@ -8,7 +8,11 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module + + +np_version = tuple(map(int, np.__version__.split("."))) + @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes[1:])) def test_opt_pow_array(dtype, shape): @@ -46,8 +50,13 @@ def fkt(a, c): hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, shape), random(dtype, shape) ao, ah = np.copysign(np.power(np.abs(ao), 1. / 8.), ao).astype(dtype), np.copysign(np.power(np.abs(ah), 1. / 8.), ah).astype(dtype) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + ao[ao == 0] += 1 + ah[ah == 0] += 1 + + if np_version >= (1, 12, 0): + # numpy 1.12 introduce incompatible change which disallows negative exponents for integers + ao = ao.astype(np.float) + fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) @@ -62,8 +71,13 @@ def fkt(a, c): hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, []), random(dtype, [1]) ao, ah = np.copysign(np.power(np.abs(ao), 1. / 8.), ao).astype(dtype), np.copysign(np.power(np.abs(ah), 1. / 8.), ah).astype(dtype) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + if ao == 0: + ao += 1 + if ah == 0: + ah += 1 + if np_version >= (1, 12, 0): + # numpy 1.12 introduce incompatible change which disallows negative exponents for integers + ao = ao.astype(np.float) fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) @@ -78,8 +92,8 @@ def fkt(a, c): hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, shape), random(dtype, shape) ao, ah = np.copysign(np.power(np.abs(ao), 1. / 4.), ao).astype(dtype), np.copysign(np.power(np.abs(ah), 1. / 4.), ah).astype(dtype) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + ao[ao == 0] += 1 + ah[ah == 0] += 1 fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) @@ -94,8 +108,10 @@ def fkt(a, c): hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, []), random(dtype, [1]) ao, ah = np.copysign(np.power(np.abs(ao), 1. / 4.), ao).astype(dtype), np.copysign(np.power(np.abs(ah), 1. / 4.), ah).astype(dtype) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + if ao == 0: + ao += 1 + if ah == 0: + ah += 1 fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) @@ -110,8 +126,10 @@ def fkt(a, c): hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, []), random(dtype, [1]) ao, ah = 1. / np.power(np.abs(ao), 1. / 2.).astype(dtype), 1. / np.power(np.abs(ah), 1. / 2.).astype(dtype) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + if ao == 0: + ao += 1 + if ah == 0: + ah += 1 fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) diff --git a/test/test_pycosmo.py b/test/test_pycosmo.py index 7cf8928..7830aa9 100644 --- a/test/test_pycosmo.py +++ b/test/test_pycosmo.py @@ -8,7 +8,7 @@ import numpy as np import hope, sysconfig, sys, os -from test.utilities import random, check, make_test, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, setup_module, setup_method, teardown_module def test_pycosmo_1(): def fkt_pycosmo(y, lna, k, eta, hubble_a, tdot, omega_gam, omega_neu, omega_dm_0, omega_b_0, ha, rh, r_bph_a, xc_damp): diff --git a/test/test_rangecheck.py b/test/test_rangecheck.py index 4a226f8..cb95cea 100644 --- a/test/test_rangecheck.py +++ b/test/test_rangecheck.py @@ -8,7 +8,7 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module def test_opt_pow_array(): def fkt(a, i): diff --git a/test/test_return.py b/test/test_return.py index 1e7277e..29361ac 100644 --- a/test/test_return.py +++ b/test/test_return.py @@ -8,13 +8,18 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module + + +np_version = tuple(map(int, np.__version__.split("."))) + @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes)) @make_test -def test_return_arr(a, b, c): +def test_return_arr(a, b, c): return a + @pytest.mark.parametrize("dtype,shape", itertools.product(dtypes, shapes)) def test_return_arr_expr(dtype, shape): def fkt(a, c): @@ -22,8 +27,15 @@ def fkt(a, c): hfkt = hope.jit(fkt) (ao, ah), (co, ch) = random(dtype, shape), random(dtype, shape) ao, ah = np.copysign(np.power(np.abs(ao), 1. / 8.), ao).astype(dtype), np.copysign(np.power(np.abs(ah), 1. / 8.), ah).astype(dtype) - if np.count_nonzero(ao == 0) > 0: ao[ao == 0] += 1 - if np.count_nonzero(ah == 0) > 0: ah[ah == 0] += 1 + if shape: + ao[ao == 0] += 1 + ah[ah == 0] += 1 + else: + ao = 1 if ao == 0 else ao + ah = 1 if ah == 0 else ah + if np_version >= (1, 12, 0): + # numpy 1.12 introduce incompatible change which disallows negative exponents for integers + ao = ao.astype(np.float) fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) diff --git a/test/test_serialization.py b/test/test_serialization.py index 403b7b4..5723b50 100644 --- a/test/test_serialization.py +++ b/test/test_serialization.py @@ -48,4 +48,4 @@ def test_unserialize_inexistent(self): def tear_down(self): shutil.rmtree(config.prefix) - config.prefix = self.prefix \ No newline at end of file + config.prefix = self.prefix diff --git a/test/test_slice.py b/test/test_slice.py index 43c8f5c..e8bb109 100644 --- a/test/test_slice.py +++ b/test/test_slice.py @@ -8,7 +8,7 @@ import hope import itertools, pytest -from test.utilities import random, check, make_test, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, dtypes, shapes, setup_module, setup_method, teardown_module @pytest.mark.parametrize("dtype", dtypes) def test_assignment(dtype): @@ -111,4 +111,4 @@ def fkt(a, c): fkt(ao, co), hfkt(ah, ch) assert check(co, ch) fkt(ao, co), hfkt(ah, ch) - assert check(co, ch) \ No newline at end of file + assert check(co, ch) diff --git a/test/test_slice_negative.py b/test/test_slice_negative.py index 2d91be7..d6c85a4 100644 --- a/test/test_slice_negative.py +++ b/test/test_slice_negative.py @@ -11,7 +11,7 @@ import pytest import numpy as np -from test.utilities import setup_module, setup_method, teardown_module +from .utilities import setup_module, setup_method, teardown_module from hope.exceptions import UnsupportedFeatureException def test_negative_idx_1d(): diff --git a/test/test_tosource.py b/test/test_tosource.py index 93a4906..4df06b8 100644 --- a/test/test_tosource.py +++ b/test/test_tosource.py @@ -14,20 +14,29 @@ from hope import _tosource from hope import _transformer + def dummy(par, *args, **kwargs): for _ in range(1): continue assert True, "msg" + +def dummy2(): + """used to test for differences between ast of python 3.4 and previous versions""" + kws = dict(c=7) + args = (1, 2) + return dummy(1, *args, **kws) + dummy(2, **{'c': 7}) + + @pytest.mark.infrastructure class TestToSource(object): - + def test_tosource_mod(self): self.exec_test_on_mod(hope._tosource) - + def test_wrapper_mod(self): self.exec_test_on_mod(hope._wrapper) - + def test_simple(self): mod_ast = _transformer.get_fkt_ast(dummy) mod_source = _tosource.tosource(mod_ast) @@ -35,12 +44,18 @@ def test_simple(self): # f.write(mod_source) mod_ast2 = ast.parse(mod_source) assert compare_ast(mod_ast, mod_ast2.body[0]) - + + def test_simple_2(self): + mod_ast = _transformer.get_fkt_ast(dummy2) + mod_source = _tosource.tosource(mod_ast) + mod_ast2 = ast.parse(mod_source) + assert compare_ast(mod_ast, mod_ast2.body[0]) + def exec_test_on_mod(self, mod): modpath = mod.__file__ if modpath.endswith('.pyc'): modpath = modpath[:-1] - + with open(modpath, "r") as f: source = f.read() mod_ast = ast.parse(source) @@ -48,7 +63,7 @@ def exec_test_on_mod(self, mod): mod_source = mod_source.replace("'\\n'", "@@@@") mod_source = mod_source.replace("\\n", "\n") mod_source = mod_source.replace("@@@@", "'\\n'") - + # with open("dummy.py", "w") as f: # f.write(mod_source) mod_ast2 = ast.parse(mod_source) @@ -68,4 +83,4 @@ def compare_ast(node1, node2): elif isinstance(node1, list): return all(itertools.starmap(compare_ast, zip(node1, node2))) else: - return node1 == node2 \ No newline at end of file + return node1 == node2 diff --git a/test/test_ufig.py b/test/test_ufig.py index ce00a7a..417f03f 100644 --- a/test/test_ufig.py +++ b/test/test_ufig.py @@ -8,7 +8,10 @@ import numpy as np import hope, itertools, pytest, sys, sysconfig, os, shutil -from test.utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module +from .utilities import random, check, make_test, JENKINS, min_dtypes, dtypes, shapes, setup_module, setup_method, teardown_module + + +np_version = tuple(map(int, np.__version__.split("."))) #hope.config.keeptemp = True @@ -92,11 +95,13 @@ def test_ufig_bincount(): def fkt_bincount(buffer, x, y, size, size_x, size_y): for idx in range(size): - if x[idx]>= 0 and x[idx] <= size_x and y[idx] >= 0 and y[idx] <= size_y: - buffer[x[idx], y[idx]] += 1. + if x[idx] >= 0 and x[idx] <= size_x and y[idx] >= 0 and y[idx] <= size_y: + x_bin = np.uint64(x[idx]) + y_bin = np.uint64(y[idx]) + buffer[x_bin, y_bin] += 1. hope.config.optimize = True hbincount = hope.jit(fkt_bincount) - + x = np.random.uniform(-1, 6, size=(1000,)) y = np.random.uniform(-1, 6, size=x.shape) buffer, hbuffer = np.zeros((5, 5)), np.zeros((5, 5)) @@ -156,4 +161,4 @@ def fkt_pdf(density, dims, center, w2D, r50, b, a): if np.all(hdensity == 1): print("asdf") else: - print("else") \ No newline at end of file + print("else") diff --git a/tox.ini b/tox.ini index d6d2c8b..ca66154 100644 --- a/tox.ini +++ b/tox.ini @@ -1,36 +1,46 @@ [tox] -envlist = py27, py33, py34, docs-ci +envlist = py27, py35, py36 [testenv] -setenv = - PYTHONPATH = {toxinidir}:{toxinidir}/hope deps = - -r{toxinidir}/requirements.txt + pip>=9.0.0 + setuptools>=34.0.0 + numpy commands = - py.test --basetemp={envtmpdir} --junitxml=junit-{envname}.xml --cov-report xml --cov hope + pip install -r requirements.txt + pip install -e . # in case we have to compile c extensions + py.test -v --basetemp={envtmpdir} --cov-report term-missing --cov-report html --cov hope tests [testenv:style] deps = - -r{toxinidir}/requirements.txt + pylint flake8 commands = - python setup.py flake8 - + pylint --disable R0913,R0914 hope tests + flake8 tests hope + [testenv:docs] -changedir=docs/ +basepython = + python3.5 + deps = - -r{toxinidir}/requirements.txt - sphinx + pip>=9.0.0 + setuptools>=34.0.0 + numpy + jupyter + numba + Cython + numexpr + version_information commands = - sphinx-build -b linkcheck ./ _build/ - sphinx-build -b html ./ _build/ - -[testenv:docs-ci] -whitelist_externals = mv -changedir=docs/ -deps = - -r{toxinidir}/requirements.txt - sphinx -commands= - py.test --tb=line -v --junitxml=junit-{envname}.xml check_sphinx.py --cov-report xml --cov hope - mv coverage.xml ../. + pip install -r requirements.txt + pip install -e . # in case we have to compile c extensions + + ./render_benchmarks_to_html.sh + sphinx-build -b linkcheck docs/ docs/_build/ # checks external links + sphinx-build -b html docs/ docs/_build/ + rm -fr docs/_build/htmlcov + mv htmlcov docs/_build + mkdir -p docs/_build/benchmarks + /bin/bash -c "mv benchmarks/*.html docs/_build/benchmarks" + /bin/bash -c "mv benchmarks/*.ipynb docs/_build/benchmarks"