diff --git a/.gitignore b/.gitignore index 32a9d13575e401b4e255ca58d0639bf65c7ff449..53d23a2f248309040f5a5e3d558c3237612e1f76 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ __pycache__ .ipynb_checkpoints -.coverage +.coverage* *.pyc *.vti /build @@ -18,4 +18,4 @@ pystencils/boundaries/createindexlistcython.c pystencils/boundaries/createindexlistcython.*.so pystencils_tests/tmp pystencils_tests/kerncraft_inputs/.2d-5pt.c_kerncraft/ -pystencils_tests/kerncraft_inputs/.3d-7pt.c_kerncraft/ \ No newline at end of file +pystencils_tests/kerncraft_inputs/.3d-7pt.c_kerncraft/ diff --git a/doc/notebooks/01_tutorial_getting_started.ipynb b/doc/notebooks/01_tutorial_getting_started.ipynb index 89a593710c9279335f86cfab6ce82becae80a6cf..564f7e0174744ecdd7be2574a313aae2534c4d74 100644 --- a/doc/notebooks/01_tutorial_getting_started.ipynb +++ b/doc/notebooks/01_tutorial_getting_started.ipynb @@ -66,7 +66,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "7.11 ms ± 137 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" + "7.96 ms ± 797 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" ] } ], @@ -89,15 +89,9 @@ "outputs": [ { "data": { + "text/plain": " src_E src_N src_S src_W\ndst_C := ───── + ───── + ───── + ─────\n 4 4 4 4 ", "image/png": "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\n", - "text/latex": [ - "$\\displaystyle {{dst}_{(0,0)}} \\leftarrow \\frac{{{src}_{(1,0)}}}{4} + \\frac{{{src}_{(0,1)}}}{4} + \\frac{{{src}_{(0,-1)}}}{4} + \\frac{{{src}_{(-1,0)}}}{4}$" - ], - "text/plain": [ - " src_E src_N src_S src_W\n", - "dst_C := ───── + ───── + ───── + ─────\n", - " 4 4 4 4 " - ] + "text/latex": "$\\displaystyle {{dst}_{(0,0)}} \\leftarrow \\frac{{{src}_{(1,0)}}}{4} + \\frac{{{src}_{(0,1)}}}{4} + \\frac{{{src}_{(0,-1)}}}{4} + \\frac{{{src}_{(-1,0)}}}{4}$" }, "execution_count": 5, "metadata": {}, @@ -119,10 +113,8 @@ "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 216x216 with 1 Axes>" - ] + "text/plain": "<Figure size 216x216 with 1 Axes>", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -180,7 +172,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "1.49 ms ± 5.93 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" + "1.76 ms ± 74 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n" ] } ], @@ -232,9 +224,7 @@ "outputs": [ { "data": { - "text/plain": [ - "sympy.core.symbol.Symbol" - ] + "text/plain": "sympy.core.symbol.Symbol" }, "execution_count": 11, "metadata": {}, @@ -261,14 +251,9 @@ "outputs": [ { "data": { + "text/plain": " 2 2\nx â‹…(x + y + 5) + x ", "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKoAAAAYCAYAAABqdGb8AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFRElEQVRoBe2b63HUMBDHDyYFAKmA0AGPDpIOklBBoAMYvuVbBjoIVACkg4QK8ugAOoC5DsL/ZySNzpb8kGXd3eCd0UnW8+/d1e5KTh7c398vhtLp6ekjjflgxu2Z/ET1y6Fzzf1nDlgOtOnVju00MP+oSd/aMSqfq3yr9MzWzfnMgQQORPXqYcJkDHkj5dz3xn5UeU91z726uThzYCgHonqVqqhY05uhKOr9pdg2bKg3zc8jOLDFfI3qVZKiihGflfx4lAV+qe6uL3/V9536zha4L8NMP/GtwTPVPVLyNz3eDf5uFQlzVK9SY1THAE0O4w6VXrjKjoLG0H9X+aeOrnNzkwM/xDcOs9YoUIYc/9V+pfRcCVf6+V/zdv2CX4idXiVZVPvKmoxdTHz6QmXfwtoujVz9YOwH5e8bjXNFHw78USd4jSDh5YVSg//iL0bgreG3ittDwtzQq2SLaiZ7r/wAFphn8l8dLEGxuSUoQsLDoQ9XuBGWJQOeO81x1JN58Bl+uxuanuNctwx43Vx9CloPJW3oVZJFNZPBhHOVcTHsbiwku72LjtW/pNJgdUibQsXwGD7D7zHvXxIvShrUq1SLyp0pL0DuSAxp3blqJ+bosrhuvrmQhQPw+1ippHFIBR7VK6eoZte9MSu8Un6ihIa/NnXX6kM8tFD+2NQNzQgTrmKDhmCIzZGz3sPDh4xbPTthm7Yvyvu64WzQtCZywlDsKiGjM9XZw5UeVwh+w3eHfaV14gfDp9F65bt+vgp8Ign7tdIXpX0949JhCrHOWHqpCX62TFICQ8vyjSYOffDjUqn+/lgpPERpQhbfjKyQDYlNRCweIviNMq+Lssi0UlS9JBrvC2KpZ4Rgd+GTWrsekwgmB+PYghh6ARce4m42LIRFquNu9Q7VqAl+hOtACflUpDKuHasZO6CCey2KKmzZ9Mq6/hvzwtXL64c7OU6XFUOU53JvKLxjsl3M5KMwCCOCClkV1lyoPRQ/t52g/Q8YWM8z5vGItep1rnkCPG7uQAFlxftxu1E/A/CMgWilifCOkqkPuFJUgazHNyHB+OOyl8di0PiQIi5Uj2dAgIM+Lqi/3aQoJIK23oU5sbbUtcXbWfFoLdYlBHmi3F3uU+9RSCHbjIMbqjmnwJtNryrX79CqIMBWMNXBiTbV8YkuxAR/aJ8ybqhznokx9MHp98GbOO9iGuDRUjjrgvDHTVEmxg/xz3qNEB76w/e10liZ7hgF/K63IOjFQrCzEILvQnJ9SWLORrxUGIMgDCLw+rxg8FriU63Lt3AOT3Vi48SsO0pcx18fn/05t0yxqLwk6Y+ZfGX3qY42e6hQcRSx47n6qlNJDPW1u55XhGz4AV7ccGniA8vKoUnP7wyI2DmiOm+UBqr1ssp0RxOyE4m/mHihF+f78KUSDOECFgV2YQB9RtBXjcV616kkhvraXc9YMO5LuRX5rWT/ODxmwbrmS24XBg54eD6rrFhLDMtT1S0jEyPXYPwZ6Z+rOqtMH6T8K8qYNxFDudc7Uo51nZy0TtJhKgZM86Gw+8pjB5rY0Ko+N562xbQWYQtGx26utu7BtpJ4gwBMJa6/NCHokjscSxOzNq3vLiFhvdxnYpU5mHA3eNY6sL0xGU/7tMFWvAH8HkMl8UZxFreoIJHAie8IMVbivyjKNTUIH9afuLC62lJO2IL7DR1o1oQyvKwwYk3BzsFv64kYdR1E4I/QN52JKCT3lhxYcJ8IvnhsqnVTiDi2pOdKwdh7zFosKugkcHb8ofJBF/G93+w/7iiesrEulG+0xxoior/cLWUUiDm0fAAAAABJRU5ErkJggg==\n", - "text/latex": [ - "$\\displaystyle x^{2} \\left(x + y + 5\\right) + x^{2}$" - ], - "text/plain": [ - " 2 2\n", - "x â‹…(x + y + 5) + x " - ] + "text/latex": "$\\displaystyle x^{2} \\left(x + y + 5\\right) + x^{2}$" }, "execution_count": 12, "metadata": {}, @@ -294,14 +279,9 @@ "outputs": [ { "data": { + "text/plain": " 3 2 2\nx + x â‹…y + 6â‹…x ", "image/png": "iVBORw0KGgoAAAANSUhEUgAAAIYAAAAXCAYAAADOQzd3AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEbUlEQVRoBeWZ7VHcMBCGD4YCSNIB6QBIBUAHkFQAdBCGf/xjoINABYR0AKmAjxJIBbm5DsjzGMsjzNnBn+eb2xmdZFnafbVa7a58S8/Pz6OqdHJyssacbcqYYvsL5ZT+R+pBExhXAXicghS7tE//5KW5OL9lulipqYYz5j3B+ML51N+pflM++DxwOgPvYcBI+wftB8rn0LdAdaEulmsq4ZR5V9HcT7T1HvNABxiD3i6QRr5G33roWKC6UBe1PAZKzIeMXZSpgueB9Bb38wC0B4yFuliqk2MEwBiIIeQb5Yr2eeifpxrcGvQu9SKGkldbFeuikWHIFWYmc9eUG9pzZRzgNXyIfYP2XCSf4Mx7Zg9l3oOzpGqU10Vjw1B8ytQETgU3BlltSfVGg9MbiYnnHu3BG0WKVyM+on3rqql9Xqdu5O2Y/0YXlXMMmOgh/lC2aAcjCIrdpD/00Xwfwcdk0AQwueW8b1b9UchRESp4Ry7ps/VTfa7lM+HddI0agd4hMYpUmnvRCDP8puqijmFMYDbOAXLRGsdPSh1ygZbOKVWEnkLDCDcRk7CjjoXXXiM4Te7FuhVjpD8x7LivSrtMF5UNIxW8R30M47/psx+45iVOG/LcJOuMWIvGMVQSmwdy0jLAQl1khoFQlXWQCnaj9ym6GW8d0h1jftmgNlxUDhnO7YIqYv/vR7iIn7H7gecsxKXvLqk9HH2RIdoPinoN98MDKbZr+uLQMuK5yj4W6mIZ5oH8CnZuoeOOcknZ5lkXq7B8NkzXYKht7HpD9XBDya/7K3269j5J/Uub7ofYKHoRDSOPpRVdJIYBcz1FrIAJzwoMJ+Vj7j2Pw6C2scPPU+nBkIzh5lMx2ffqlMYv226DJxiFt4+wH0GMOZ3eKxlD3do+hlByD9M4u91A4CN9GsiIuhW3CR+TPhPVPGl4ypkW58VRJr9t7LrsECb1Dqc5sOLP92VDmNvFGuUf70+QZ46gMRhqNNbWdJEYRqQIeCc0TSHhXe0aOdM2fkS/3snrqu67EjEnbGKY1wg7/MJh0AA8idkp5Z3exL5Cj8GYVtcoHgoik1uf9TQyFxwxrjVdxDlGIhDmQSFJopkKXKVfhQyaWsaul8q8ZrpwdeNG5Tega71oiGX6f+NNmupiJd1wP56YtAhAi3fxsTCTsa7v+YitRh1j9xTGOhBcr/lFpA3Dk3uUJ0O+e3Xbti70GJ4CyzhlPqadEX2+C8lY1j+QRpfYXxlFqgfleVPplZCt93bzswsCbT2IYdPPClKruliBoV7COCrjEQIPKf4hppWa3GgwWVhxzICoS+x6SDN+NyN8N3DpyuydwLEjFor7Ipmwx39LtKqLVv5ES2A2+GGxtZPPBmIrTXVTmLBNrfuuTPOwxnhRb5LP+GWP7QmyLIMgjYCit0yItm7ba2HhNfVlZOnvoNZYipSXhpKZE4qfiXsuWbgeLLhsh/kV+AKctUPqANfougppEKGkEN2MXrCJGoYxXE8x9T+JGUHrTew/A0Y1bcMwkZ8AAAAASUVORK5CYII=\n", - "text/latex": [ - "$\\displaystyle x^{3} + x^{2} y + 6 x^{2}$" - ], - "text/plain": [ - " 3 2 2\n", - "x + x â‹…y + 6â‹…x " - ] + "text/latex": "$\\displaystyle x^{3} + x^{2} y + 6 x^{2}$" }, "execution_count": 13, "metadata": {}, @@ -319,14 +299,9 @@ "outputs": [ { "data": { + "text/plain": " 2 \nx â‹…(x + y + 6)", "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHoAAAAYCAYAAAA1Zem1AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEpklEQVRoBe2Z3VEjMQzHF4YCcpQQOuCjAkIHwFUA6QCGJ3hjuA6ACjjoIFwFfHQAHRyXDrj/b1l7nMVrYidr8rCaceSVLVkrWbK8WXp/fy9i4ezsrCeek4qvX+ED0cexsrr5eSywkrjMhZw6NLzqX6r/pLZmaB1eLAssJ6pzKOcOHN4L9fuirTu0rrtAFkh1NNH8OOt7aGOYtD+rqI7fsYDPrkmOlqArNfc8xvGvoj076wW7mnukCV0GCFopeZDsin0tLKUUY5ZbHQnEWbdqG+q7znenTfQ1b1eELeHjiYHuYWoLyHYcly7ciGYDTX0cPRa+YtJMjpYQUi+F2J760zq5p/l/NH9DuINIC1Q2J7CO1b+HXZjndeGJYljPFMjbwuPUqrsQM05msR1h8wx+5TkA7EQ2RxaQPhSNpLJyZ2dZNLDIHPTBqURv6eRqKYLHZ3fsjL2HSY7WIiaScbQ5Zzmnp0nF++KxVzPxtA0YgbYokKyP7MaRh7233ZcRvQw2l0ZfdGqpf2rHSY6WDFICCoMtSGDQgRpHUd/OszK6TtAC2JdzdxycNTmIvfeto8WM4w6rOVvCB2pE7s+K9qA5d/SFf1S0WMTOc1POBH+MDhOMLT04+nD2PenZpv9q7Fp4r6XlfWI3ReR2Q1Tjl79q6HYrWpNdoe8s68cAX7t+0UR4ULtWG+iZdMwmqFd5IkUDir4EuHLoEFj+09BJZY+RRurvvy8aGSon4AdgE7+gmxpRjqObdMHe/dLRmkQkuy9CaoDR7ODV2rgekwBF33ycGXXwLf+JJn2IGjY8QCaq6x3MTiXXHH+kj3Ey1bXxi1nhtzpkFzPH0MHo3Tep+1GT3LOTq8+zaDi8EJ5XemLDlDKRW4OZdJCOVJiDmkweWZN38NUPvGPTu7kfgIjec+Q4wFp1mh1uQR8j2/WToVErEaxkzHoKZ36vdLSUshdtEQHfi32MtPQ7qw7i9zmyEJ3MxPWKI2lq0HyzyXEokWKjSGNEO7S6UUX6AM2Zuz6SifCmQGGMmqoOZXC5Z3Q5QcLMi5WFF0TRerS6hIRn0siXclrWIVZtIt5mt4oZG1H91gMkVnbsfDZWyH6+aGf+20rlQC7hFEIIYifyEi4TRck0d2SxBgGZn3ZdZh2CCnoG0de1BVOyns+OThxP+KoOHLX4zJdhiOhXIprdSXurDE7UWRCNMVOUWHpihwjY8vDm1MGzfJA04eTKHuhLJZ4VtDZZ9l7YFs7qE7EctQcNypT11gqMapw/KF+Icag2UmP3cMizAWwaZ84McCNe347MqUOs+mQyKlqMa+6tyPBFD/RWQXrsoIsa/gGIWL5nNx0j+HU4058arBILUoh7HX+CNCkWKzI4X+skFWNNQiUPhw+Ek/6Umbc+TXpC11ocOwTtGqk7N2Aob0XakiJjyaVFgwxE5JDVSlCfNMk15vyDkvSbrE/CamQj7F0U/B+du52eno7U+rnXjV1POr6oHRk+9W/VLszzImPp2VcbGR05o78DuLJwVlO9LjIQEauK5CNhvilfqv8tZ3OCkTjDbebMfkYbhWUwzo9d4agPGYa/w80WqDbmnbC9MfwH+JA6Vr0VD58AAAAASUVORK5CYII=\n", - "text/latex": [ - "$\\displaystyle x^{2} \\left(x + y + 6\\right)$" - ], - "text/plain": [ - " 2 \n", - "x â‹…(x + y + 6)" - ] + "text/latex": "$\\displaystyle x^{2} \\left(x + y + 6\\right)$" }, "execution_count": 14, "metadata": {}, @@ -344,14 +319,9 @@ "outputs": [ { "data": { + "text/plain": " 2 2\nx â‹…(x + cos(x) + 5) + x ", "image/png": "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\n", - "text/latex": [ - "$\\displaystyle x^{2} \\left(x + \\cos{\\left(x \\right)} + 5\\right) + x^{2}$" - ], - "text/plain": [ - " 2 2\n", - "x â‹…(x + cos(x) + 5) + x " - ] + "text/latex": "$\\displaystyle x^{2} \\left(x + \\cos{\\left(x \\right)} + 5\\right) + x^{2}$" }, "execution_count": 15, "metadata": {}, @@ -376,14 +346,9 @@ "outputs": [ { "data": { + "text/plain": " 2 2 \nx â‹…(x + y + 5) + x = 1", "image/png": "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\n", - "text/latex": [ - "$\\displaystyle x^{2} \\left(x + y + 5\\right) + x^{2} = 1$" - ], - "text/plain": [ - " 2 2 \n", - "x â‹…(x + y + 5) + x = 1" - ] + "text/latex": "$\\displaystyle x^{2} \\left(x + y + 5\\right) + x^{2} = 1$" }, "execution_count": 16, "metadata": {}, @@ -402,16 +367,9 @@ "outputs": [ { "data": { + "text/plain": "⎡ 1 ⎤\n⎢-x - 6 + ──⎥\n⎢ 2⎥\n⎣ x ⎦", "image/png": "iVBORw0KGgoAAAANSUhEUgAAAH8AAAAzCAYAAAC+J9cEAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEwElEQVR4Ae2d7VEUQRCGD8sAUDPADAAj4MhANAIgAyl+wT8LM0AiQMhAjQAkA8lAvAz0fZaZrblhl9u728+b7qpmZmd3Z7r7ne752ivWTk5O1kcFdHp6OikotqIBWkBYFmL8Qrr8Ev+N+GyAOprI5Ra4ivAF76s1ef5vZQ7VO36Uv2t3VskCwvpA+uy9XCWlVl0XgbYpHfHiLeWXHpYN/J73GIHMeH0hfhBvizfEtZCBX4sZm6vEefgeLSj/SQneXwsx4TNK1AIGfqLAo7aBb+AnbIGEVTfPN/ATtkDCqpvnG/gJWyBh1c3zDfyELTAs1d84cV/XIbZt79ZhxYbr0LYuhznQ+DEZXansXvnvSr+6srmTpMGX4eLvFi5Vdje3FRt+QTJle/t1N5Mk+DLmhgyJNx0pn33HoJRr+K04CUp1wgfIeHn4AQtHp4TSuUn1jMV8IDEoSs7zBdJ7IcSx6E6IlMp3w+s583QceFCUoucfCqGJwJ4MCqkGhG3c82VkPMKHxHfK74sZcz+KoRs9c/2YbeUvX8Pcq028Hxn+iBnnmUGHw4CKVpva8PwzGfULLFPeiPkkiTHySCkdI55xq6hR8uF5GxmcbEQDwGdISIYaBV/GxONDcAm1GNivTdmsCO/rsjmSPB74TeW9DL7Bb8pcBM/48pVNnw37zhA/pb03WhVD7Ok9v1a+VT6cQW+pgjuV0QlGSmeuX/UMbS8jA03FFMrk7/H7BTorw0Jh+Jcs57o3FseU7bjpPhEkJvStoue/+MU6rtX2Wlk9s8AHJABbiNSw7wT+/Q/KfPYXVVLVsZQMYRvUJaYo63zhvSDPfKSQ9G4RuCOVE802lDK0LUR6txSkhSqs8FKjYT9sX8rhMXhxPrlT2TocPtdCHq9+rs2iqNCCWO038aznLyOOA5XNFCZ8GByvwfNC4x7rmolfm0ToRq6YiHDIVxjy44dX4box8GUcPB1mRo2n8aODnFTGPWb/rZLavQZgMZ0y63hKkY8hiWXoYMjJfewE9sPVvsonVZRoEnw8iBk1II8kEL8H5BQKz2Ny9aB8PgTwTFukdnfFgI8sEBO2HV3Hc5TsZo//oEM+D3H6YNtK5xONgS9B6H25YBhQZYDdCeC0H5JkaXu4CZuvK38gPcLNKZbNlLGUndmRW5vw1aVtT+uho1cKtTXLj3PdLlpnY56/qEBDfE9e1skkUe3GG1V0BrauZ3o9djbPH2JvK5BZgHNWwX5D5X0ZA7/AkEMrEvDM9Bnv5/rdvoX9niEtINclUuVTUAc8y+nsewR3PVIa7qcUammeX2iWTgtZvlU6BXVAs1w9V54ZPqGfVczUnkqZNub5ZZbpoFzglZ2C+s0n9iPCU1DW9EQK0pxUz9QSO78RZQz8yCAdX851CiqQXy0jr4X9ZaxX87sCM16iseV8WXMzeXUGfm6KfmXUEcaSiJCe74iqrNZTUAv7PcEcYCVKq6eg5vk9AV9i4OkwB150hKkZu4sEtZ6CmufLyj2h1k9BDfyeIC/PnkiUqSWayho9BbWw3xPwuxDDwO/C6j1p08DvCRBdiOHHfD47ZoaZkxuD8mvLDNcCMbbSJMPaez6HA+E/XAj3j4ertUnuLcD+wRN8/wN7Ln/yKtUUoQAAAABJRU5ErkJggg==\n", - "text/latex": [ - "$\\displaystyle \\left[ - x - 6 + \\frac{1}{x^{2}}\\right]$" - ], - "text/plain": [ - "⎡ 1 ⎤\n", - "⎢-x - 6 + ──⎥\n", - "⎢ 2⎥\n", - "⎣ x ⎦" - ] + "text/latex": "$\\displaystyle \\left[ - x - 6 + \\frac{1}{x^{2}}\\right]$" }, "execution_count": 17, "metadata": {}, @@ -436,14 +394,9 @@ "outputs": [ { "data": { + "text/plain": " 2 2\nx â‹…(x + y + 5) + x ", "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKoAAAAYCAYAAABqdGb8AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAFRElEQVRoBe2b63HUMBDHDyYFAKmA0AGPDpIOklBBoAMYvuVbBjoIVACkg4QK8ugAOoC5DsL/ZySNzpb8kGXd3eCd0UnW8+/d1e5KTh7c398vhtLp6ekjjflgxu2Z/ET1y6Fzzf1nDlgOtOnVju00MP+oSd/aMSqfq3yr9MzWzfnMgQQORPXqYcJkDHkj5dz3xn5UeU91z726uThzYCgHonqVqqhY05uhKOr9pdg2bKg3zc8jOLDFfI3qVZKiihGflfx4lAV+qe6uL3/V9536zha4L8NMP/GtwTPVPVLyNz3eDf5uFQlzVK9SY1THAE0O4w6VXrjKjoLG0H9X+aeOrnNzkwM/xDcOs9YoUIYc/9V+pfRcCVf6+V/zdv2CX4idXiVZVPvKmoxdTHz6QmXfwtoujVz9YOwH5e8bjXNFHw78USd4jSDh5YVSg//iL0bgreG3ittDwtzQq2SLaiZ7r/wAFphn8l8dLEGxuSUoQsLDoQ9XuBGWJQOeO81x1JN58Bl+uxuanuNctwx43Vx9CloPJW3oVZJFNZPBhHOVcTHsbiwku72LjtW/pNJgdUibQsXwGD7D7zHvXxIvShrUq1SLyp0pL0DuSAxp3blqJ+bosrhuvrmQhQPw+1ippHFIBR7VK6eoZte9MSu8Un6ihIa/NnXX6kM8tFD+2NQNzQgTrmKDhmCIzZGz3sPDh4xbPTthm7Yvyvu64WzQtCZywlDsKiGjM9XZw5UeVwh+w3eHfaV14gfDp9F65bt+vgp8Ign7tdIXpX0949JhCrHOWHqpCX62TFICQ8vyjSYOffDjUqn+/lgpPERpQhbfjKyQDYlNRCweIviNMq+Lssi0UlS9JBrvC2KpZ4Rgd+GTWrsekwgmB+PYghh6ARce4m42LIRFquNu9Q7VqAl+hOtACflUpDKuHasZO6CCey2KKmzZ9Mq6/hvzwtXL64c7OU6XFUOU53JvKLxjsl3M5KMwCCOCClkV1lyoPRQ/t52g/Q8YWM8z5vGItep1rnkCPG7uQAFlxftxu1E/A/CMgWilifCOkqkPuFJUgazHNyHB+OOyl8di0PiQIi5Uj2dAgIM+Lqi/3aQoJIK23oU5sbbUtcXbWfFoLdYlBHmi3F3uU+9RSCHbjIMbqjmnwJtNryrX79CqIMBWMNXBiTbV8YkuxAR/aJ8ybqhznokx9MHp98GbOO9iGuDRUjjrgvDHTVEmxg/xz3qNEB76w/e10liZ7hgF/K63IOjFQrCzEILvQnJ9SWLORrxUGIMgDCLw+rxg8FriU63Lt3AOT3Vi48SsO0pcx18fn/05t0yxqLwk6Y+ZfGX3qY42e6hQcRSx47n6qlNJDPW1u55XhGz4AV7ccGniA8vKoUnP7wyI2DmiOm+UBqr1ssp0RxOyE4m/mHihF+f78KUSDOECFgV2YQB9RtBXjcV616kkhvraXc9YMO5LuRX5rWT/ODxmwbrmS24XBg54eD6rrFhLDMtT1S0jEyPXYPwZ6Z+rOqtMH6T8K8qYNxFDudc7Uo51nZy0TtJhKgZM86Gw+8pjB5rY0Ko+N562xbQWYQtGx26utu7BtpJ4gwBMJa6/NCHokjscSxOzNq3vLiFhvdxnYpU5mHA3eNY6sL0xGU/7tMFWvAH8HkMl8UZxFreoIJHAie8IMVbivyjKNTUIH9afuLC62lJO2IL7DR1o1oQyvKwwYk3BzsFv64kYdR1E4I/QN52JKCT3lhxYcJ8IvnhsqnVTiDi2pOdKwdh7zFosKugkcHb8ofJBF/G93+w/7iiesrEulG+0xxoior/cLWUUiDm0fAAAAABJRU5ErkJggg==\n", - "text/latex": [ - "$\\displaystyle x^{2} \\left(x + y + 5\\right) + x^{2}$" - ], - "text/plain": [ - " 2 2\n", - "x â‹…(x + y + 5) + x " - ] + "text/latex": "$\\displaystyle x^{2} \\left(x + y + 5\\right) + x^{2}$" }, "execution_count": 18, "metadata": {}, @@ -461,162 +414,8 @@ "outputs": [ { "data": { - "image/svg+xml": [ - "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", - "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n", - " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n", - "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n", - " -->\n", - "<!-- Title: %3 Pages: 1 -->\n", - "<svg width=\"426pt\" height=\"260pt\"\n", - " viewBox=\"0.00 0.00 426.00 260.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", - "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n", - "<title>%3</title>\n", - "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-256 422,-256 422,4 -4,4\"/>\n", - "<!-- Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_() -->\n", - "<g id=\"node1\" class=\"node\">\n", - "<title>Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"136\" cy=\"-234\" rx=\"29.4969\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"136\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Add</text>\n", - "</g>\n", - "<!-- Pow(Symbol('x'), Integer(2))_(0,) -->\n", - "<g id=\"node2\" class=\"node\">\n", - "<title>Pow(Symbol('x'), Integer(2))_(0,)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"98\" cy=\"-162\" rx=\"30.5947\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"98\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Pow</text>\n", - "</g>\n", - "<!-- Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Pow(Symbol('x'), Integer(2))_(0,) -->\n", - "<g id=\"edge1\" class=\"edge\">\n", - "<title>Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Pow(Symbol('x'), Integer(2))_(0,)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M126.8013,-216.5708C122.3203,-208.0807 116.8379,-197.6929 111.8634,-188.2674\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"114.877,-186.4789 107.114,-179.2687 108.6863,-189.7462 114.877,-186.4789\"/>\n", - "</g>\n", - "<!-- Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,) -->\n", - "<g id=\"node5\" class=\"node\">\n", - "<title>Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"175\" cy=\"-162\" rx=\"28.6953\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"175\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Mul</text>\n", - "</g>\n", - "<!-- Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,) -->\n", - "<g id=\"edge2\" class=\"edge\">\n", - "<title>Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M145.4408,-216.5708C150.0396,-208.0807 155.6664,-197.6929 160.7718,-188.2674\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"163.9608,-189.7286 165.6461,-179.2687 157.8057,-186.3946 163.9608,-189.7286\"/>\n", - "</g>\n", - "<!-- Symbol('x')_(0, 0) -->\n", - "<g id=\"node3\" class=\"node\">\n", - "<title>Symbol('x')_(0, 0)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"27\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"27\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">x</text>\n", - "</g>\n", - "<!-- Pow(Symbol('x'), Integer(2))_(0,)->Symbol('x')_(0, 0) -->\n", - "<g id=\"edge3\" class=\"edge\">\n", - "<title>Pow(Symbol('x'), Integer(2))_(0,)->Symbol('x')_(0, 0)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M82.5941,-146.3771C72.7854,-136.4302 59.9251,-123.3888 49.0442,-112.3547\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"51.4029,-109.7619 41.8893,-105.099 46.4187,-114.6769 51.4029,-109.7619\"/>\n", - "</g>\n", - "<!-- Integer(2)_(0, 1) -->\n", - "<g id=\"node4\" class=\"node\">\n", - "<title>Integer(2)_(0, 1)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"99\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"99\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">2</text>\n", - "</g>\n", - "<!-- Pow(Symbol('x'), Integer(2))_(0,)->Integer(2)_(0, 1) -->\n", - "<g id=\"edge4\" class=\"edge\">\n", - "<title>Pow(Symbol('x'), Integer(2))_(0,)->Integer(2)_(0, 1)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M98.2523,-143.8314C98.3593,-136.131 98.4865,-126.9743 98.6053,-118.4166\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"102.1049,-118.4609 98.7443,-108.4133 95.1056,-118.3637 102.1049,-118.4609\"/>\n", - "</g>\n", - "<!-- Pow(Symbol('x'), Integer(2))_(1, 0) -->\n", - "<g id=\"node6\" class=\"node\">\n", - "<title>Pow(Symbol('x'), Integer(2))_(1, 0)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"175\" cy=\"-90\" rx=\"30.5947\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"175\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Pow</text>\n", - "</g>\n", - "<!-- Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Pow(Symbol('x'), Integer(2))_(1, 0) -->\n", - "<g id=\"edge5\" class=\"edge\">\n", - "<title>Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Pow(Symbol('x'), Integer(2))_(1, 0)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M175,-143.8314C175,-136.131 175,-126.9743 175,-118.4166\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"178.5001,-118.4132 175,-108.4133 171.5001,-118.4133 178.5001,-118.4132\"/>\n", - "</g>\n", - "<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1) -->\n", - "<g id=\"node9\" class=\"node\">\n", - "<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"286\" cy=\"-90\" rx=\"29.4969\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"286\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Add</text>\n", - "</g>\n", - "<!-- Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1) -->\n", - "<g id=\"edge6\" class=\"edge\">\n", - "<title>Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M195.1013,-148.9613C212.438,-137.7159 237.684,-121.3401 257.173,-108.6986\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"259.1882,-111.5633 265.6732,-103.185 255.3789,-105.6905 259.1882,-111.5633\"/>\n", - "</g>\n", - "<!-- Symbol('x')_(1, 0, 0) -->\n", - "<g id=\"node7\" class=\"node\">\n", - "<title>Symbol('x')_(1, 0, 0)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"103\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"103\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">x</text>\n", - "</g>\n", - "<!-- Pow(Symbol('x'), Integer(2))_(1, 0)->Symbol('x')_(1, 0, 0) -->\n", - "<g id=\"edge7\" class=\"edge\">\n", - "<title>Pow(Symbol('x'), Integer(2))_(1, 0)->Symbol('x')_(1, 0, 0)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M159.3771,-74.3771C149.4302,-64.4302 136.3888,-51.3888 125.3547,-40.3547\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"127.645,-37.6953 118.099,-33.099 122.6953,-42.645 127.645,-37.6953\"/>\n", - "</g>\n", - "<!-- Integer(2)_(1, 0, 1) -->\n", - "<g id=\"node8\" class=\"node\">\n", - "<title>Integer(2)_(1, 0, 1)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"175\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"175\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">2</text>\n", - "</g>\n", - "<!-- Pow(Symbol('x'), Integer(2))_(1, 0)->Integer(2)_(1, 0, 1) -->\n", - "<g id=\"edge8\" class=\"edge\">\n", - "<title>Pow(Symbol('x'), Integer(2))_(1, 0)->Integer(2)_(1, 0, 1)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M175,-71.8314C175,-64.131 175,-54.9743 175,-46.4166\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"178.5001,-46.4132 175,-36.4133 171.5001,-46.4133 178.5001,-46.4132\"/>\n", - "</g>\n", - "<!-- Integer(5)_(1, 1, 0) -->\n", - "<g id=\"node10\" class=\"node\">\n", - "<title>Integer(5)_(1, 1, 0)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"247\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"247\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">5</text>\n", - "</g>\n", - "<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Integer(5)_(1, 1, 0) -->\n", - "<g id=\"edge9\" class=\"edge\">\n", - "<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Integer(5)_(1, 1, 0)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M276.5592,-72.5708C271.9604,-64.0807 266.3336,-53.6929 261.2282,-44.2674\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"264.1943,-42.3946 256.3539,-35.2687 258.0392,-45.7286 264.1943,-42.3946\"/>\n", - "</g>\n", - "<!-- Symbol('x')_(1, 1, 1) -->\n", - "<g id=\"node11\" class=\"node\">\n", - "<title>Symbol('x')_(1, 1, 1)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"319\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"319\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">x</text>\n", - "</g>\n", - "<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('x')_(1, 1, 1) -->\n", - "<g id=\"edge10\" class=\"edge\">\n", - "<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('x')_(1, 1, 1)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M293.9884,-72.5708C297.8392,-64.1691 302.5417,-53.9091 306.8256,-44.5623\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"310.1003,-45.8177 311.0852,-35.2687 303.7369,-42.901 310.1003,-45.8177\"/>\n", - "</g>\n", - "<!-- Symbol('y')_(1, 1, 2) -->\n", - "<g id=\"node12\" class=\"node\">\n", - "<title>Symbol('y')_(1, 1, 2)</title>\n", - "<ellipse fill=\"none\" stroke=\"#000000\" cx=\"391\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"391\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">y</text>\n", - "</g>\n", - "<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('y')_(1, 1, 2) -->\n", - "<g id=\"edge11\" class=\"edge\">\n", - "<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('y')_(1, 1, 2)</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M305.7497,-76.4574C322.0864,-65.2551 345.4675,-49.2223 363.6128,-36.7798\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"365.7782,-39.5388 372.0461,-30.997 361.8194,-33.7657 365.7782,-39.5388\"/>\n", - "</g>\n", - "</g>\n", - "</svg>\n" - ], - "text/plain": [ - "<graphviz.files.Source at 0x7f9701574250>" - ] + "text/plain": "<graphviz.files.Source at 0x7fa1081625b0>", + "image/svg+xml": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<!-- Generated by graphviz version 2.43.0 (0)\n -->\n<!-- Title: %3 Pages: 1 -->\n<svg width=\"425pt\" height=\"260pt\"\n viewBox=\"0.00 0.00 425.00 260.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 256)\">\n<title>%3</title>\n<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-256 421,-256 421,4 -4,4\"/>\n<!-- Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_() -->\n<g id=\"node1\" class=\"node\">\n<title>Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"136\" cy=\"-234\" rx=\"28.7\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"136\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">Add</text>\n</g>\n<!-- Pow(Symbol('x'), Integer(2))_(0,) -->\n<g id=\"node2\" class=\"node\">\n<title>Pow(Symbol('x'), Integer(2))_(0,)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"98\" cy=\"-162\" rx=\"29.8\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"98\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Pow</text>\n</g>\n<!-- Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Pow(Symbol('x'), Integer(2))_(0,) -->\n<g id=\"edge1\" class=\"edge\">\n<title>Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Pow(Symbol('x'), Integer(2))_(0,)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M127.19,-216.76C122.65,-208.4 117.01,-198.02 111.9,-188.61\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"114.88,-186.75 107.03,-179.63 108.72,-190.09 114.88,-186.75\"/>\n</g>\n<!-- Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,) -->\n<g id=\"node5\" class=\"node\">\n<title>Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"174\" cy=\"-162\" rx=\"28.7\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"174\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Mul</text>\n</g>\n<!-- Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,) -->\n<g id=\"edge2\" class=\"edge\">\n<title>Add(Pow(Symbol('x'), Integer(2)), Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y'))))_()->Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M144.81,-216.76C149.42,-208.28 155.16,-197.71 160.32,-188.2\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"163.54,-189.61 165.23,-179.15 157.39,-186.27 163.54,-189.61\"/>\n</g>\n<!-- Symbol('x')_(0, 0) -->\n<g id=\"node3\" class=\"node\">\n<title>Symbol('x')_(0, 0)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"27\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">x</text>\n</g>\n<!-- Pow(Symbol('x'), Integer(2))_(0,)->Symbol('x')_(0, 0) -->\n<g id=\"edge3\" class=\"edge\">\n<title>Pow(Symbol('x'), Integer(2))_(0,)->Symbol('x')_(0, 0)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M82.94,-146.15C73.02,-136.37 59.87,-123.4 48.81,-112.5\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"51.13,-109.87 41.55,-105.35 46.21,-114.86 51.13,-109.87\"/>\n</g>\n<!-- Integer(2)_(0, 1) -->\n<g id=\"node4\" class=\"node\">\n<title>Integer(2)_(0, 1)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-90\" rx=\"27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"99\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n</g>\n<!-- Pow(Symbol('x'), Integer(2))_(0,)->Integer(2)_(0, 1) -->\n<g id=\"edge4\" class=\"edge\">\n<title>Pow(Symbol('x'), Integer(2))_(0,)->Integer(2)_(0, 1)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M98.25,-143.7C98.36,-135.98 98.49,-126.71 98.61,-118.11\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"102.11,-118.15 98.76,-108.1 95.11,-118.05 102.11,-118.15\"/>\n</g>\n<!-- Pow(Symbol('x'), Integer(2))_(1, 0) -->\n<g id=\"node6\" class=\"node\">\n<title>Pow(Symbol('x'), Integer(2))_(1, 0)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"174\" cy=\"-90\" rx=\"29.8\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"174\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Pow</text>\n</g>\n<!-- Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Pow(Symbol('x'), Integer(2))_(1, 0) -->\n<g id=\"edge5\" class=\"edge\">\n<title>Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Pow(Symbol('x'), Integer(2))_(1, 0)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M174,-143.7C174,-135.98 174,-126.71 174,-118.11\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"177.5,-118.1 174,-108.1 170.5,-118.1 177.5,-118.1\"/>\n</g>\n<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1) -->\n<g id=\"node9\" class=\"node\">\n<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"284\" cy=\"-90\" rx=\"28.7\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"284\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Add</text>\n</g>\n<!-- Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1) -->\n<g id=\"edge6\" class=\"edge\">\n<title>Mul(Pow(Symbol('x'), Integer(2)), Add(Integer(5), Symbol('x'), Symbol('y')))_(1,)->Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M193.41,-148.65C210.74,-137.62 236.33,-121.33 255.9,-108.88\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"257.85,-111.79 264.41,-103.47 254.1,-105.88 257.85,-111.79\"/>\n</g>\n<!-- Symbol('x')_(1, 0, 0) -->\n<g id=\"node7\" class=\"node\">\n<title>Symbol('x')_(1, 0, 0)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"102\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"102\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">x</text>\n</g>\n<!-- Pow(Symbol('x'), Integer(2))_(1, 0)->Symbol('x')_(1, 0, 0) -->\n<g id=\"edge7\" class=\"edge\">\n<title>Pow(Symbol('x'), Integer(2))_(1, 0)->Symbol('x')_(1, 0, 0)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M158.73,-74.15C148.67,-64.37 135.33,-51.4 124.11,-40.5\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"126.36,-37.81 116.75,-33.35 121.49,-42.83 126.36,-37.81\"/>\n</g>\n<!-- Integer(2)_(1, 0, 1) -->\n<g id=\"node8\" class=\"node\">\n<title>Integer(2)_(1, 0, 1)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"174\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"174\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">2</text>\n</g>\n<!-- Pow(Symbol('x'), Integer(2))_(1, 0)->Integer(2)_(1, 0, 1) -->\n<g id=\"edge8\" class=\"edge\">\n<title>Pow(Symbol('x'), Integer(2))_(1, 0)->Integer(2)_(1, 0, 1)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M174,-71.7C174,-63.98 174,-54.71 174,-46.11\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"177.5,-46.1 174,-36.1 170.5,-46.1 177.5,-46.1\"/>\n</g>\n<!-- Integer(5)_(1, 1, 0) -->\n<g id=\"node10\" class=\"node\">\n<title>Integer(5)_(1, 1, 0)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"246\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"246\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">5</text>\n</g>\n<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Integer(5)_(1, 1, 0) -->\n<g id=\"edge9\" class=\"edge\">\n<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Integer(5)_(1, 1, 0)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M275.19,-72.76C270.58,-64.28 264.84,-53.71 259.68,-44.2\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"262.61,-42.27 254.77,-35.15 256.46,-45.61 262.61,-42.27\"/>\n</g>\n<!-- Symbol('x')_(1, 1, 1) -->\n<g id=\"node11\" class=\"node\">\n<title>Symbol('x')_(1, 1, 1)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"318\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"318\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">x</text>\n</g>\n<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('x')_(1, 1, 1) -->\n<g id=\"edge10\" class=\"edge\">\n<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('x')_(1, 1, 1)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M292.06,-72.41C296.08,-64.13 301.04,-53.92 305.54,-44.66\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"308.78,-45.99 310,-35.47 302.48,-42.94 308.78,-45.99\"/>\n</g>\n<!-- Symbol('y')_(1, 1, 2) -->\n<g id=\"node12\" class=\"node\">\n<title>Symbol('y')_(1, 1, 2)</title>\n<ellipse fill=\"none\" stroke=\"black\" cx=\"390\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"390\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">y</text>\n</g>\n<!-- Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('y')_(1, 1, 2) -->\n<g id=\"edge11\" class=\"edge\">\n<title>Add(Integer(5), Symbol('x'), Symbol('y'))_(1, 1)->Symbol('y')_(1, 1, 2)</title>\n<path fill=\"none\" stroke=\"black\" d=\"M302.95,-76.49C319.71,-65.42 344.35,-49.15 363.14,-36.74\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"365.15,-39.6 371.57,-31.17 361.29,-33.76 365.15,-39.6\"/>\n</g>\n</g>\n</svg>\n" }, "execution_count": 19, "metadata": {}, @@ -642,9 +441,7 @@ "outputs": [ { "data": { - "text/plain": [ - "sympy.core.add.Add" - ] + "text/plain": "sympy.core.add.Add" }, "execution_count": 20, "metadata": {}, @@ -662,14 +459,9 @@ "outputs": [ { "data": { + "text/plain": "⎛ 2 2 ⎞\nâŽx , x â‹…(x + y + 5)⎠", "image/png": "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\n", - "text/latex": [ - "$\\displaystyle \\left( x^{2}, \\ x^{2} \\left(x + y + 5\\right)\\right)$" - ], - "text/plain": [ - "⎛ 2 2 ⎞\n", - "âŽx , x â‹…(x + y + 5)⎠" - ] + "text/latex": "$\\displaystyle \\left( x^{2}, \\ x^{2} \\left(x + y + 5\\right)\\right)$" }, "execution_count": 21, "metadata": {}, @@ -719,13 +511,9 @@ "outputs": [ { "data": { + "text/plain": "f_E__1", "image/png": "iVBORw0KGgoAAAANSUhEUgAAACkAAAAdCAYAAAA3i0VNAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACxklEQVRYCdWX7VEbMRCGwUMBHtKB00E+OrA7cOggoQOY/LL/MdAB6YCBDgwVJEMHcQd46MB5HvlOnGXd4bPHmOzMWqvV7urVrqSTD+fz+UFbGo/HXXxO4FPkz23929oftXUA1Cd8+oWfYHdOm4B8BNUjYIc7R1dM0HmribaZ578A2VhuSnpNBp6LLFzQL+VtEtPatzaTALok2jF8A/+Ay8OC+LZUCxIYAhOgQP/A9/BeKFtusmjWvF7uixLvDaBZyYJEP4CnuT2IrsfYKexCevTdFk+0V7Q7ocPqF4eJLLEABTCDvRNn6AW1PxJkyqPRaA6fpfp99VcODlmznNJe9+ECwuJ3BSRqv80HgLXU74JyIL+CbNqEjgUMKxlvMt1ojNhnVcfc6TaTtVkkgIfLkx8Xgux11erpho+3gvQEf6B/Hnr8IF/B13A4sLlMfsHud+lQbXESzIA27ldkFyVwx+RXCR/tvbbOYa+uCe0kcbxFFxayBBJlD0MnqsukTn7PI+Hjs82JYmbjYL1gnOpClfvF/MELudR1l0AyWh6aGCB4vPwYqG7sxapBKoCYiHRRz+jC/BX3ADQF6UV+VzGKYhHcQNuSAHM0Q3mcDLjtBh0m96TeFoPux5vEsOy6FQy0KxJgugCT0jOT7o8uQIMBbTaTRQCdtqW6GM6fboGQlBKkJ0uw3xoQGCAspMHm1SGSYByBWpmU0gOrzfQIp1+pZa6Pnac4FzhnHnX4uLCftPEepH8B+4gJoBhTvqNNM+l8f5deQSgaiSBm3P/aMRiygcqnm6fT6yg+3RhX9wB/R45bCdnKSV7mH2HvTDMciX6Yb+UF1PTS4WXUhy+bbOrG8BvWjeX02HfhiWOdCHsNgZV5b3nIWpUde8vZ9n4107WfxUa4TKijJW9ziHzBL5WyaRJs/Wz6WVxsq1yq19FZjnXsNrFJY/8DzKtH71g9xXgAAAAASUVORK5CYII=\n", - "text/latex": [ - "$\\displaystyle {{f}_{(1,0)}^{1}}$" - ], - "text/plain": [ - "f_E__1" - ] + "text/latex": "$\\displaystyle {{f}_{(1,0)}^{1}}$" }, "execution_count": 23, "metadata": {}, @@ -751,9 +539,7 @@ "outputs": [ { "data": { - "text/plain": [ - "True" - ] + "text/plain": "True" }, "execution_count": 24, "metadata": {}, @@ -789,17 +575,9 @@ "outputs": [ { "data": { + "text/plain": " \n(img_E__2â‹…wâ‚‚ - img_NE__2â‹…wâ‚ - img_NW__2â‹…wâ‚ + img_SE__2â‹…wâ‚ - img_SW__2â‹…wâ‚ - img\n\n 2\n_W__2â‹…wâ‚‚) ", "image/png": "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\n", - "text/latex": [ - "$\\displaystyle \\left({{img}_{(1,0)}^{2}} w_{2} - {{img}_{(1,1)}^{2}} w_{1} - {{img}_{(-1,1)}^{2}} w_{1} + {{img}_{(1,-1)}^{2}} w_{1} - {{img}_{(-1,-1)}^{2}} w_{1} - {{img}_{(-1,0)}^{2}} w_{2}\\right)^{2}$" - ], - "text/plain": [ - " \n", - "(img_E__2â‹…wâ‚‚ - img_NE__2â‹…wâ‚ - img_NW__2â‹…wâ‚ + img_SE__2â‹…wâ‚ - img_SW__2â‹…wâ‚ - img\n", - "\n", - " 2\n", - "_W__2â‹…wâ‚‚) " - ] + "text/latex": "$\\displaystyle \\left({{img}_{(1,0)}^{2}} w_{2} - {{img}_{(1,1)}^{2}} w_{1} - {{img}_{(-1,1)}^{2}} w_{1} + {{img}_{(1,-1)}^{2}} w_{1} - {{img}_{(-1,-1)}^{2}} w_{1} - {{img}_{(-1,0)}^{2}} w_{2}\\right)^{2}$" }, "execution_count": 26, "metadata": {}, @@ -828,17 +606,9 @@ "outputs": [ { "data": { + "text/plain": " \n(img_E__2â‹…wâ‚‚ - 0.5â‹…img_NE__2 - 0.5â‹…img_NW__2 + 0.5â‹…img_SE__2 - 0.5â‹…img_SW__2 -\n\n 2\n img_W__2â‹…wâ‚‚) ", "image/png": "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\n", - "text/latex": [ - "$\\displaystyle \\left({{img}_{(1,0)}^{2}} w_{2} - 0.5 {{img}_{(1,1)}^{2}} - 0.5 {{img}_{(-1,1)}^{2}} + 0.5 {{img}_{(1,-1)}^{2}} - 0.5 {{img}_{(-1,-1)}^{2}} - {{img}_{(-1,0)}^{2}} w_{2}\\right)^{2}$" - ], - "text/plain": [ - " \n", - "(img_E__2â‹…wâ‚‚ - 0.5â‹…img_NE__2 - 0.5â‹…img_NW__2 + 0.5â‹…img_SE__2 - 0.5â‹…img_SW__2 -\n", - "\n", - " 2\n", - " img_W__2â‹…wâ‚‚) " - ] + "text/latex": "$\\displaystyle \\left({{img}_{(1,0)}^{2}} w_{2} - 0.5 {{img}_{(1,1)}^{2}} - 0.5 {{img}_{(-1,1)}^{2}} + 0.5 {{img}_{(1,-1)}^{2}} - 0.5 {{img}_{(-1,-1)}^{2}} - {{img}_{(-1,0)}^{2}} w_{2}\\right)^{2}$" }, "execution_count": 27, "metadata": {}, @@ -864,17 +634,9 @@ "outputs": [ { "data": { + "text/plain": " \ndst_C := (img_E__2â‹…wâ‚‚ - 0.5â‹…img_NE__2 - 0.5â‹…img_NW__2 + 0.5â‹…img_SE__2 - 0.5â‹…im\n\n 2\ng_SW__2 - img_W__2â‹…wâ‚‚) ", "image/png": "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\n", - "text/latex": [ - "$\\displaystyle {{dst}_{(0,0)}} \\leftarrow \\left({{img}_{(1,0)}^{2}} w_{2} - 0.5 {{img}_{(1,1)}^{2}} - 0.5 {{img}_{(-1,1)}^{2}} + 0.5 {{img}_{(1,-1)}^{2}} - 0.5 {{img}_{(-1,-1)}^{2}} - {{img}_{(-1,0)}^{2}} w_{2}\\right)^{2}$" - ], - "text/plain": [ - " \n", - "dst_C := (img_E__2â‹…wâ‚‚ - 0.5â‹…img_NE__2 - 0.5â‹…img_NW__2 + 0.5â‹…img_SE__2 - 0.5â‹…im\n", - "\n", - " 2\n", - "g_SW__2 - img_W__2â‹…wâ‚‚) " - ] + "text/latex": "$\\displaystyle {{dst}_{(0,0)}} \\leftarrow \\left({{img}_{(1,0)}^{2}} w_{2} - 0.5 {{img}_{(1,1)}^{2}} - 0.5 {{img}_{(-1,1)}^{2}} + 0.5 {{img}_{(1,-1)}^{2}} - 0.5 {{img}_{(-1,-1)}^{2}} - {{img}_{(-1,0)}^{2}} w_{2}\\right)^{2}$" }, "execution_count": 28, "metadata": {}, @@ -915,15 +677,13 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 30, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 1152x432 with 1 Axes>" - ] + "text/plain": "<Figure size 1152x432 with 1 Axes>", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -948,15 +708,13 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 31, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAA64AAAFQCAYAAAC/ASMyAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nOzdW4wjWXon9v8JBoPBa5J5r0tXVXd191TPRTPCtGSgJUA2BruWDcHyPtiQHhaGYXj2RYAN+MHyPhiGnwxj1/vmhWdhwXqwvWvD1nofBFuCYMvwgwWNGqNxa7p6pquzqqvyyuT9EowIkscPVd+pIIuZyTuZlf8fUKiqTF4imWTE+c73ne8orTWIiIiIiIiI1pW16gMgIiIiIiIiugwDVyIiIiIiIlprDFyJiIiIiIhorTFwJSIiIiIiorXGwJWIiIiIiIjWGgNXIiIiIiIiWmsLC1yVUr+plPpCKfWlUur3F/U8RERERERE9HZTi9jHVSkVA/BzAH8LwAsAfwngd7XWP5v7kxEREREREdFbbVEZ118F8KXW+iutdQDgnwL47QU9FxEREREREb3F7AU97h0AzyP/fwHgX7roxkqp+ad9iYiIiIiIaF2ca613pr3zogJXNeJrA8GpUuqHAH4o/9/Z2cHW1taCDoeIiIiIiIiWrVQqoVgsAsCzWR5nUYHrCwDvRP5/F8BR9AZa6x8B+BHwMuO6tbWFR48eLehwiIiIiIiIaNkeP34sgetMFrXG9S8BfKCUelcp5QD4HQD/YkHPRURERERERG+xhWRctdZdpdTvAfg/AMQA/IHW+m8W8VxERERERET0dltUqTC01n8M4I8X9fhERERERER0MyyqVJiIiIiIiIhoLhi4EhERERER0Vpj4EpERERERERrjYErERERERERrTUGrkRERERERLTWGLgSERERERHRWmPgSkRERERERGuNgSsRERERERGtNQauREREREREtNYYuBIREREREdFaY+BKREREREREa42BKxEREREREa01Bq5ERERERES01hi4EhERERER0Vpj4EpERERERERrjYErERERERERrTUGrkRERERERLTWGLgSERERERHRWmPgSkRERERERGuNgSsRERERERGtNQauREREREREtNYYuBIREREREdFaY+BKREREREREa42BKxER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\n", - "text/plain": [ - "<Figure size 1152x432 with 1 Axes>" - ] + "text/plain": "<Figure size 1152x432 with 1 Axes>", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA64AAAFQCAYAAAC/ASMyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAACNbUlEQVR4nO39eYxkW34f+H1PrDf2iNyrsra3db9+vZJskZwWJXLUw3FLJkjJGNAk7BmOTLglmAQkQMaYkgFrLECAbGsZCzJot4YckgOJIk2KFDGgx6Q5NDkWhhx2t1qt7n7V3a9eVb3KPTP29d5Yjv/I/J26ERXLjf1m5vcDJCor1huRN27c3/n9zu8orTWIiIiIiIiI/Cqw7g0gIiIiIiIiGoeBKxEREREREfkaA1ciIiIiIiLyNQauRERERERE5GsMXImIiIiIiMjXGLgSERERERGRry0tcFVKfU4p9U2l1HtKqZ9Z1vMQERERERHRzaaWsY6rUioI4FsAfhDAAYA/AfDjWutvLPzJiIiIiIiI6EZbVsb1uwG8p7V+X2vtAPgXAH5kSc9FREREREREN1hoSY+7D+CF6/8HAL5n1I2VUotP+xIREREREZFfXGitt2e987IC14mUUp8H8Hn5//b2NjY3N9e1OURERERERLRg+Xwe5+fnAPB8nsdZVuB6COC+6//3ri4ztNZfAPAF4DLjurm5ibfffntJm0NERERERESr9vjxYwlc57KsOa5/AuAtpdRrSqkIgB8D8FtLei4iIiIiIiK6wZaScdVad5RSPw3g/w0gCODntdZfX8ZzERERERER0c22tDmuWuvfBvDby3p8IiIiIiIiuh2WVSpMREREREREtBAMXImIiIiIiMjXGLgSERERERGRrzFwJSIiIiIiIl9j4EpERERERES+xsCViIiIiIiIfI2BKxEREREREfkaA1ciIiIiIiLyNQauRERERERE5GsMXImIiIiIiMjXGLgSERERERGRrzFwJSIiIiIiIl9j4EpERERERES+xsCViIiIiIiIfI2BKxEREREREfkaA1ciIiIiIiLyNQauRERERERE5GsMXImIiIiIiMjXGLgSERERERGRrzFwJSIiIiIiIl9j4EpERERERES+xsCViIiIiIiIfI2BKxEREREREfkaA1ciIiIiIiLyNQauRERERERE5GsMXImIiIiIiMjX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8jUGrkRERERERORrDFyJiIiIiIjI1xi4EhERERERka8xcCUiIiIiIiJfY+BKREREREREvsbAlYiIiIiIiHyNgSsRERERERH5GgNXIiIiIiIi8jUGrkRERERERORrDFyJiIiIiIjI1xi4EhERERERka8xcCUiIiIiIiJfY+BKREREREREvsbAlYiIiIiIiHyNgSsRERERERH5GgNXIiIiIiIi8jUGrkRERERERORrDFyJiIiIiIjI1xi4EhERERERka8xcCUiIiIiIiJfY+BKREREREREvsbAlYiIiIiIiHyNgSsRERERERH52sTAVSl1Xyn1+0qpbyilvq6U+mtXl28opX5XKfXtq39zV5crpdQ/Vkq9p5T6qlLqO5f9IoiIiIiIiOjm8pJx7QD4G1rrdwB8L4CfUkq9A+BnAPye1votAL939X8A+PMA3rr6+TyAn134VhMREREREdGtMTFw1Vofa62/fPV7FcC7APYB/AiAX7y62S8C+ItXv/8IgF/Sl/4IQFYpdWfRG05ERERERES3w1RzXJVSjwB8B4A/BrCrtT6+uuoEwO7V7/sAXrjudnB1GREREREREdHUQl5vqJRKAvh1AH9da11RSpnrtNZaKaWneWKl1OdxWUpMRERERERENJKnjKtSKozLoPWfaa3/5dXFp1ICfPXv2dXlhwDuu+5+7+qyPlrrL2itP621/vSsG09EREREREQ338SMq7pMrf4cgHe11v/QddVvAfgJAH/v6t9/5br8p5VS/wLA9wAou0qKR8rn83j8+PGUm09ERERERER+dXFxsZDHUVqPr/BVSn0fgP8ewL8D0Lu6+G/hcp7rrwJ4AOA5gB/VWheuAt1/AuBzABoA/rLW+osTnmOqMmMiIiIiIiK6Vr40T7XtxMB1FZRS5wDqABYTjhNd2gL3KVoc7k+0aNynaJG4P9GicZ+iRdoCkNBab8/6AL4IXAFAKfVFznelReI+RYvE/YkWjfsULRL3J1o07lO0SIvYn6ZaDoeIiIiIiIho1Ri4EhERERERka/5KXD9wro3gG4c7lO0SNyfaNG4T9EicX+iReM+RYs09/7kmzmuRERERERERMP4KeNKRERERERE9ApfBK5Kqc8ppb6plHpPKfUz694e8j+l1M8rpc6UUl9zXbahlPpdpdS3r/7NXV2ulFL/+Gr/+qpS6jvXt+XkR0qp+0qp31dKfUMp9XWl1F+7upz7FM1EKWUppf5HpdS/vdqn/o9Xl7+mlPrjq33nV5RSkavLo1f/f+/q+kdrfQHkS0qpoFLq3yil/pur/3N/opkppZ4ppf6dUuorSqkvXl3G7z2amVIqq5T6NaXUY6XUu0qpf2+R+9TaA1elVBDA/w3AnwfwDoAfV0q9s96tomvgFwB8buCynwHwe1rrtwD83tX/gct9662rn88D+NkVbSNdHx0Af0Nr/Q6A7wXwU1fHIe5TNCsbwJ/TWn8SwKcAfE4p9b0A/k8A/pHW+k0ARQA/eXX7nwRQvLr8H13djmjQXwPwruv/3J9oXv++1vpTrmVK+L1H8/i/AvhvtdZvA/gkLo9XC9un1h64AvhuAO9prd/XWjsA/gWAH1nzNpHPaa3/EEBh4OIfAfCLV7//IoC/6Lr8l/SlPwKQVUrdWcmG0rWgtT7WWn/56vcqLg+0++A+RTO62jdqV/8NX/1oAH8OwK9dXT64T8m+9msAPquUUqvZWroOlFL3APxPAfyXV/9X4P5Ei8fvPZqJUioD4M8C+DkA0Fo7WusSFrhP+SFw3QfwwvX/g6vLiKa1q7U+vvr9BMDu1e/cx8izq5K67wDwx+A+RXO4Kuv8CoAzAL8L4AmAkta6c3UT935j9qmr68sANle6weR3/wWA/wxA7+r/m+D+RPPRAH5HKfUlpdTnry7j9x7N6jUA5wD+q6spDf+lUiqBBe5TfghciRZOX7bLZstsmopSKgng1wH8da11xX0d9ymalta6q7X+FIB7uKwuenu9W0TXlVLqhwCcaa2/tO5toRvl+7TW34nLks2fUkr9WfeV/N6jKYUAfCeAn9VafweAOl6WBQOYf5/yQ+B6COC+6//3ri4jmtaplBhc/Xt2dTn3MZpIKRXGZdD6z7TW//LqYu5TNLerUqnfB/Dv4bIUKnR1lXu/MfvU1fUZAPnVbin52J8G8MNKqWe4nFL153A5l4z7E81Ma3149e8ZgN/A5QAbv/doVgcADrTWf3z1/1/DZSC7sH3KD4HrnwB466ozXgTAjwH4rTVvE11PvwXgJ65+/wkA/8p1+X9y1b3sewGUXSULRDJX7OcAvKu1/oeuq7hP0UyUUttKqezV7zEAP4jLudO/D+A/urrZ4D4l+9p/BOC/01xona5orf+m1vqe1voRLs+T/jut9f8C3J9oRkqphFIqJb8D+A8BfA383qMZaa1PALxQSn346qLPAvgGFrhPKT8cx5RSfwGXczeCAH5ea/1317tF5HdKqV8G8AMAtgCcAvjbAH4TwK8CeADgOYAf1VoXroKSf4LLLsQNAH9Za/3FNWw2+ZRS6vsA/PcA/h1ezh/7W7ic58p9iqamlPoELptQBHE5SPyrWuu/o5R6HZcZsw0A/wbA/1JrbSulLAD/NS7nVxcA/JjW+v31bD35mVLqBwD8b7XWP8T9iWZ1te/8xtV/QwD+udb67yqlNsHvPZqRUupTuGwgFwHwPoC/jKvvQCxgn/JF4EpEREREREQ0ih9KhYmIiIiIiIhGYuBKREREREREvsbAlYiIiIiIiHyNgSsRERERERH5GgNXIiIiIiIi8jUGrkRERERERORrDFyJiIiIiIjI1xi4EhERERERka/9/wF/ZcHULakkhgAAAABJRU5ErkJggg==\n" }, "metadata": { "needs_background": "light" @@ -987,150 +745,8 @@ "outputs": [ { "data": { - "image/svg+xml": [ - "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", - "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n", - " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n", - "<!-- Generated by graphviz version 2.40.1 (20161225.0304)\n", - " -->\n", - "<!-- Title: %3 Pages: 1 -->\n", - "<svg width=\"684pt\" height=\"384pt\"\n", - " viewBox=\"0.00 0.00 684.00 383.91\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", - "<g id=\"graph0\" class=\"graph\" transform=\"scale(.8065 .8065) rotate(0) translate(4 472)\">\n", - "<title>%3</title>\n", - "<polygon fill=\"#ffffff\" stroke=\"transparent\" points=\"-4,4 -4,-472 844.0784,-472 844.0784,4 -4,4\"/>\n", - "<!-- 140286538387600 -->\n", - "<g id=\"node1\" class=\"node\">\n", - "<title>140286538387600</title>\n", - "<ellipse fill=\"#a056db\" stroke=\"#000000\" cx=\"269.1436\" cy=\"-450\" rx=\"135.6761\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"269.1436\" y=\"-446.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Func: kernel (dst,img,w_2)</text>\n", - "</g>\n", - "<!-- 140286539358736 -->\n", - "<g id=\"node11\" class=\"node\">\n", - "<title>140286539358736</title>\n", - "<ellipse fill=\"#dbc256\" stroke=\"#000000\" cx=\"269.1436\" cy=\"-378\" rx=\"37.0935\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"269.1436\" y=\"-374.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Block</text>\n", - "</g>\n", - "<!-- 140286538387600->140286539358736 -->\n", - "<g id=\"edge10\" class=\"edge\">\n", - "<title>140286538387600->140286539358736</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M269.1436,-431.8314C269.1436,-424.131 269.1436,-414.9743 269.1436,-406.4166\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"272.6437,-406.4132 269.1436,-396.4133 265.6437,-406.4133 272.6437,-406.4132\"/>\n", - "</g>\n", - "<!-- 140286538521232 -->\n", - "<g id=\"node2\" class=\"node\">\n", - "<title>140286538521232</title>\n", - "<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"179.1436\" cy=\"-306\" rx=\"75.2868\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"179.1436\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_img_22</text>\n", - "</g>\n", - "<!-- 140286575500560 -->\n", - "<g id=\"node3\" class=\"node\">\n", - "<title>140286575500560</title>\n", - "<ellipse fill=\"#3498db\" stroke=\"#000000\" cx=\"359.1436\" cy=\"-306\" rx=\"86.3847\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"359.1436\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Loop over dim 0</text>\n", - "</g>\n", - "<!-- 140286539326864 -->\n", - "<g id=\"node10\" class=\"node\">\n", - "<title>140286539326864</title>\n", - "<ellipse fill=\"#dbc256\" stroke=\"#000000\" cx=\"359.1436\" cy=\"-234\" rx=\"37.0935\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"359.1436\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Block</text>\n", - "</g>\n", - "<!-- 140286575500560->140286539326864 -->\n", - "<g id=\"edge7\" class=\"edge\">\n", - "<title>140286575500560->140286539326864</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M359.1436,-287.8314C359.1436,-280.131 359.1436,-270.9743 359.1436,-262.4166\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"362.6437,-262.4132 359.1436,-252.4133 355.6437,-262.4133 362.6437,-262.4132\"/>\n", - "</g>\n", - "<!-- 140286538492944 -->\n", - "<g id=\"node4\" class=\"node\">\n", - "<title>140286538492944</title>\n", - "<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"72.1436\" cy=\"-162\" rx=\"72.2875\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"72.1436\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_dst_00</text>\n", - "</g>\n", - "<!-- 140286538522128 -->\n", - "<g id=\"node5\" class=\"node\">\n", - "<title>140286538522128</title>\n", - "<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"254.1436\" cy=\"-162\" rx=\"91.784\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"254.1436\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_img_22_01</text>\n", - "</g>\n", - "<!-- 140286538519184 -->\n", - "<g id=\"node6\" class=\"node\">\n", - "<title>140286538519184</title>\n", - "<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"464.1436\" cy=\"-162\" rx=\"100.9827\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"464.1436\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_img_22_0m1</text>\n", - "</g>\n", - "<!-- 140286539326928 -->\n", - "<g id=\"node7\" class=\"node\">\n", - "<title>140286539326928</title>\n", - "<ellipse fill=\"#3498db\" stroke=\"#000000\" cx=\"669.1436\" cy=\"-162\" rx=\"86.3847\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"669.1436\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Loop over dim 1</text>\n", - "</g>\n", - "<!-- 140286538390928 -->\n", - "<g id=\"node9\" class=\"node\">\n", - "<title>140286538390928</title>\n", - "<ellipse fill=\"#dbc256\" stroke=\"#000000\" cx=\"669.1436\" cy=\"-90\" rx=\"37.0935\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"669.1436\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Block</text>\n", - "</g>\n", - "<!-- 140286539326928->140286538390928 -->\n", - "<g id=\"edge2\" class=\"edge\">\n", - "<title>140286539326928->140286538390928</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M669.1436,-143.8314C669.1436,-136.131 669.1436,-126.9743 669.1436,-118.4166\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"672.6437,-118.4132 669.1436,-108.4133 665.6437,-118.4133 672.6437,-118.4132\"/>\n", - "</g>\n", - "<!-- 140286538593616 -->\n", - "<g id=\"node8\" class=\"node\">\n", - "<title>140286538593616</title>\n", - "<ellipse fill=\"#56db7f\" stroke=\"#000000\" cx=\"669.1436\" cy=\"-18\" rx=\"170.8697\" ry=\"18\"/>\n", - "<text text-anchor=\"middle\" x=\"669.1436\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">_data_dst_00[_stride_dst_1*ctr_1]</text>\n", - "</g>\n", - "<!-- 140286538390928->140286538593616 -->\n", - "<g id=\"edge1\" class=\"edge\">\n", - "<title>140286538390928->140286538593616</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M669.1436,-71.8314C669.1436,-64.131 669.1436,-54.9743 669.1436,-46.4166\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"672.6437,-46.4132 669.1436,-36.4133 665.6437,-46.4133 672.6437,-46.4132\"/>\n", - "</g>\n", - "<!-- 140286539326864->140286538492944 -->\n", - "<g id=\"edge3\" class=\"edge\">\n", - "<title>140286539326864->140286538492944</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M326.221,-225.7407C279.2459,-213.956 192.1579,-192.1081 133.1881,-177.3143\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"133.8004,-173.8595 123.2492,-174.8209 132.097,-180.6491 133.8004,-173.8595\"/>\n", - "</g>\n", - "<!-- 140286539326864->140286538522128 -->\n", - "<g id=\"edge4\" class=\"edge\">\n", - "<title>140286539326864->140286538522128</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M337.6419,-219.256C323.4673,-209.5363 304.5958,-196.5958 288.3799,-185.4764\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"289.9177,-182.287 279.691,-179.5182 285.959,-188.0601 289.9177,-182.287\"/>\n", - "</g>\n", - "<!-- 140286539326864->140286538519184 -->\n", - "<g id=\"edge5\" class=\"edge\">\n", - "<title>140286539326864->140286538519184</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M380.6453,-219.256C394.8199,-209.5363 413.6914,-196.5958 429.9073,-185.4764\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"432.3282,-188.0601 438.5962,-179.5182 428.3695,-182.287 432.3282,-188.0601\"/>\n", - "</g>\n", - "<!-- 140286539326864->140286539326928 -->\n", - "<g id=\"edge6\" class=\"edge\">\n", - "<title>140286539326864->140286539326928</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M392.6136,-226.2263C442.3238,-214.6807 536.7265,-192.7549 601.2727,-177.7636\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"602.4153,-181.0914 611.3642,-175.4197 600.8316,-174.2729 602.4153,-181.0914\"/>\n", - "</g>\n", - "<!-- 140286539358736->140286538521232 -->\n", - "<g id=\"edge8\" class=\"edge\">\n", - "<title>140286539358736->140286538521232</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M249.6149,-362.3771C237.7129,-352.8555 222.2663,-340.4982 208.8691,-329.7804\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"210.8374,-326.8729 200.8422,-323.3589 206.4645,-332.3389 210.8374,-326.8729\"/>\n", - "</g>\n", - "<!-- 140286539358736->140286575500560 -->\n", - "<g id=\"edge9\" class=\"edge\">\n", - "<title>140286539358736->140286575500560</title>\n", - "<path fill=\"none\" stroke=\"#000000\" d=\"M288.6723,-362.3771C300.4886,-352.924 315.7988,-340.6758 329.1287,-330.0119\"/>\n", - "<polygon fill=\"#000000\" stroke=\"#000000\" points=\"331.5013,-332.5961 337.1235,-323.6161 327.1284,-327.13 331.5013,-332.5961\"/>\n", - "</g>\n", - "</g>\n", - "</svg>\n" - ], - "text/plain": [ - "<graphviz.files.Source at 0x7f9700dfd5d0>" - ] + "text/plain": "<graphviz.files.Source at 0x7fa106bb71f0>", + "image/svg+xml": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<!-- Generated by graphviz version 2.43.0 (0)\n -->\n<!-- Title: %3 Pages: 1 -->\n<svg width=\"684pt\" height=\"391pt\"\n viewBox=\"0.00 0.00 684.00 390.75\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n<g id=\"graph0\" class=\"graph\" transform=\"scale(1.22 1.22) rotate(0) translate(4 472)\">\n<title>%3</title>\n<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-472 829.23,-472 829.23,4 -4,4\"/>\n<!-- 140329578519952 -->\n<g id=\"node1\" class=\"node\">\n<title>140329578519952</title>\n<ellipse fill=\"#a056db\" stroke=\"black\" cx=\"263.84\" cy=\"-450\" rx=\"134.58\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"263.84\" y=\"-446.3\" font-family=\"Times,serif\" font-size=\"14.00\">Func: kernel (dst,img,w_2)</text>\n</g>\n<!-- 140329578392784 -->\n<g id=\"node11\" class=\"node\">\n<title>140329578392784</title>\n<ellipse fill=\"#dbc256\" stroke=\"black\" cx=\"263.84\" cy=\"-378\" rx=\"36.29\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"263.84\" y=\"-374.3\" font-family=\"Times,serif\" font-size=\"14.00\">Block</text>\n</g>\n<!-- 140329578519952->140329578392784 -->\n<g id=\"edge10\" class=\"edge\">\n<title>140329578519952->140329578392784</title>\n<path fill=\"none\" stroke=\"black\" d=\"M263.84,-431.7C263.84,-423.98 263.84,-414.71 263.84,-406.11\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"267.34,-406.1 263.84,-396.1 260.34,-406.1 267.34,-406.1\"/>\n</g>\n<!-- 140329578493168 -->\n<g id=\"node2\" class=\"node\">\n<title>140329578493168</title>\n<ellipse fill=\"#56db7f\" stroke=\"black\" cx=\"175.84\" cy=\"-306\" rx=\"73.39\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"175.84\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\">_data_img_22</text>\n</g>\n<!-- 140329578389952 -->\n<g id=\"node3\" class=\"node\">\n<title>140329578389952</title>\n<ellipse fill=\"#3498db\" stroke=\"black\" cx=\"352.84\" cy=\"-306\" rx=\"85.59\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"352.84\" y=\"-302.3\" font-family=\"Times,serif\" font-size=\"14.00\">Loop over dim 0</text>\n</g>\n<!-- 140329578390240 -->\n<g id=\"node10\" class=\"node\">\n<title>140329578390240</title>\n<ellipse fill=\"#dbc256\" stroke=\"black\" cx=\"352.84\" cy=\"-234\" rx=\"36.29\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"352.84\" y=\"-230.3\" font-family=\"Times,serif\" font-size=\"14.00\">Block</text>\n</g>\n<!-- 140329578389952->140329578390240 -->\n<g id=\"edge7\" class=\"edge\">\n<title>140329578389952->140329578390240</title>\n<path fill=\"none\" stroke=\"black\" d=\"M352.84,-287.7C352.84,-279.98 352.84,-270.71 352.84,-262.11\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"356.34,-262.1 352.84,-252.1 349.34,-262.1 356.34,-262.1\"/>\n</g>\n<!-- 140329578494560 -->\n<g id=\"node4\" class=\"node\">\n<title>140329578494560</title>\n<ellipse fill=\"#56db7f\" stroke=\"black\" cx=\"70.84\" cy=\"-162\" rx=\"70.69\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"70.84\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">_data_dst_00</text>\n</g>\n<!-- 140329578492688 -->\n<g id=\"node5\" class=\"node\">\n<title>140329578492688</title>\n<ellipse fill=\"#56db7f\" stroke=\"black\" cx=\"249.84\" cy=\"-162\" rx=\"89.88\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"249.84\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">_data_img_22_01</text>\n</g>\n<!-- 140329578492544 -->\n<g id=\"node6\" class=\"node\">\n<title>140329578492544</title>\n<ellipse fill=\"#56db7f\" stroke=\"black\" cx=\"455.84\" cy=\"-162\" rx=\"98.58\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"455.84\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">_data_img_22_0m1</text>\n</g>\n<!-- 140329578390672 -->\n<g id=\"node7\" class=\"node\">\n<title>140329578390672</title>\n<ellipse fill=\"#3498db\" stroke=\"black\" cx=\"658.84\" cy=\"-162\" rx=\"85.59\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"658.84\" y=\"-158.3\" font-family=\"Times,serif\" font-size=\"14.00\">Loop over dim 1</text>\n</g>\n<!-- 140329578520000 -->\n<g id=\"node9\" class=\"node\">\n<title>140329578520000</title>\n<ellipse fill=\"#dbc256\" stroke=\"black\" cx=\"658.84\" cy=\"-90\" rx=\"36.29\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"658.84\" y=\"-86.3\" font-family=\"Times,serif\" font-size=\"14.00\">Block</text>\n</g>\n<!-- 140329578390672->140329578520000 -->\n<g id=\"edge2\" class=\"edge\">\n<title>140329578390672->140329578520000</title>\n<path fill=\"none\" stroke=\"black\" d=\"M658.84,-143.7C658.84,-135.98 658.84,-126.71 658.84,-118.11\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"662.34,-118.1 658.84,-108.1 655.34,-118.1 662.34,-118.1\"/>\n</g>\n<!-- 140329578519760 -->\n<g id=\"node8\" class=\"node\">\n<title>140329578519760</title>\n<ellipse fill=\"#56db7f\" stroke=\"black\" cx=\"658.84\" cy=\"-18\" rx=\"166.27\" ry=\"18\"/>\n<text text-anchor=\"middle\" x=\"658.84\" y=\"-14.3\" font-family=\"Times,serif\" font-size=\"14.00\">_data_dst_00[_stride_dst_1*ctr_1]</text>\n</g>\n<!-- 140329578520000->140329578519760 -->\n<g id=\"edge1\" class=\"edge\">\n<title>140329578520000->140329578519760</title>\n<path fill=\"none\" stroke=\"black\" d=\"M658.84,-71.7C658.84,-63.98 658.84,-54.71 658.84,-46.11\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"662.34,-46.1 658.84,-36.1 655.34,-46.1 662.34,-46.1\"/>\n</g>\n<!-- 140329578390240->140329578494560 -->\n<g id=\"edge3\" class=\"edge\">\n<title>140329578390240->140329578494560</title>\n<path fill=\"none\" stroke=\"black\" d=\"M321.04,-225.11C274.68,-213.6 187.72,-192.01 129.54,-177.57\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"130.29,-174.15 119.74,-175.14 128.61,-180.94 130.29,-174.15\"/>\n</g>\n<!-- 140329578390240->140329578492688 -->\n<g id=\"edge4\" class=\"edge\">\n<title>140329578390240->140329578492688</title>\n<path fill=\"none\" stroke=\"black\" d=\"M332,-218.83C317.82,-209.19 298.75,-196.24 282.56,-185.23\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"284.15,-182.08 273.91,-179.35 280.21,-187.87 284.15,-182.08\"/>\n</g>\n<!-- 140329578390240->140329578492544 -->\n<g id=\"edge5\" class=\"edge\">\n<title>140329578390240->140329578492544</title>\n<path fill=\"none\" stroke=\"black\" d=\"M373.69,-218.83C387.77,-209.26 406.67,-196.42 422.79,-185.46\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"425.11,-188.12 431.41,-179.61 421.17,-182.33 425.11,-188.12\"/>\n</g>\n<!-- 140329578390240->140329578390672 -->\n<g id=\"edge6\" class=\"edge\">\n<title>140329578390240->140329578390672</title>\n<path fill=\"none\" stroke=\"black\" d=\"M385.3,-225.58C434.58,-214.3 529.28,-192.64 593.27,-178\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"594.3,-181.35 603.27,-175.71 592.74,-174.53 594.3,-181.35\"/>\n</g>\n<!-- 140329578392784->140329578493168 -->\n<g id=\"edge8\" class=\"edge\">\n<title>140329578392784->140329578493168</title>\n<path fill=\"none\" stroke=\"black\" d=\"M245.18,-362.15C233.32,-352.72 217.72,-340.31 204.33,-329.66\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"206.33,-326.78 196.32,-323.29 201.97,-332.25 206.33,-326.78\"/>\n</g>\n<!-- 140329578392784->140329578389952 -->\n<g id=\"edge9\" class=\"edge\">\n<title>140329578392784->140329578389952</title>\n<path fill=\"none\" stroke=\"black\" d=\"M282.72,-362.15C294.63,-352.78 310.27,-340.49 323.75,-329.88\"/>\n<polygon fill=\"black\" stroke=\"black\" points=\"326.12,-332.47 331.82,-323.54 321.79,-326.97 326.12,-332.47\"/>\n</g>\n</g>\n</svg>\n" }, "execution_count": 32, "metadata": {}, @@ -1155,119 +771,16 @@ "outputs": [ { "data": { - "text/html": [ - "<style>.highlight .hll { background-color: #ffffcc }\n", - ".highlight { background: #f8f8f8; }\n", - ".highlight .c { color: #408080; font-style: italic } /* Comment */\n", - ".highlight .err { border: 1px solid #FF0000 } /* Error */\n", - ".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n", - ".highlight .o { color: #666666 } /* Operator */\n", - ".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n", - ".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n", - ".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n", - ".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n", - ".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n", - ".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n", - ".highlight .gd { color: #A00000 } /* Generic.Deleted */\n", - ".highlight .ge { font-style: italic } /* Generic.Emph */\n", - ".highlight .gr { color: #FF0000 } /* Generic.Error */\n", - ".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n", - ".highlight .gi { color: #00A000 } /* Generic.Inserted */\n", - ".highlight .go { color: #888888 } /* Generic.Output */\n", - ".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n", - ".highlight .gs { font-weight: bold } /* Generic.Strong */\n", - ".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n", - ".highlight .gt { color: #0044DD } /* Generic.Traceback */\n", - ".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n", - ".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n", - ".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n", - ".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n", - ".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n", - ".highlight .kt { color: #B00040 } /* Keyword.Type */\n", - ".highlight .m { color: #666666 } /* Literal.Number */\n", - ".highlight .s { color: #BA2121 } /* Literal.String */\n", - ".highlight .na { color: #7D9029 } /* Name.Attribute */\n", - ".highlight .nb { color: #008000 } /* Name.Builtin */\n", - ".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n", - ".highlight .no { color: #880000 } /* Name.Constant */\n", - ".highlight .nd { color: #AA22FF } /* Name.Decorator */\n", - ".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n", - ".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n", - ".highlight .nf { color: #0000FF } /* Name.Function */\n", - ".highlight .nl { color: #A0A000 } /* Name.Label */\n", - ".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n", - ".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n", - ".highlight .nv { color: #19177C } /* Name.Variable */\n", - ".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n", - ".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n", - ".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n", - ".highlight .mf { color: #666666 } /* Literal.Number.Float */\n", - ".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n", - ".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n", - ".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n", - ".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n", - ".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n", - ".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n", - ".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n", - ".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n", - ".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n", - ".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n", - ".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n", - ".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n", - ".highlight .sx { color: #008000 } /* Literal.String.Other */\n", - ".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n", - ".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n", - ".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n", - ".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n", - ".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n", - ".highlight .vc { color: #19177C } /* Name.Variable.Class */\n", - ".highlight .vg { color: #19177C } /* Name.Variable.Global */\n", - ".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n", - ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", - ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] + "text/plain": "<IPython.core.display.HTML object>", + "text/html": "<style>pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.highlight .hll { background-color: #ffffcc }\n.highlight { background: #f8f8f8; }\n.highlight .c { color: #408080; font-style: italic } /* Comment */\n.highlight .err { border: 1px solid #FF0000 } /* Error */\n.highlight .k { color: #008000; font-weight: bold } /* Keyword */\n.highlight .o { color: #666666 } /* Operator */\n.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #A00000 } /* Generic.Deleted */\n.highlight .ge { font-style: italic } /* Generic.Emph */\n.highlight .gr { color: #FF0000 } /* Generic.Error */\n.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.highlight .gi { color: #00A000 } /* Generic.Inserted */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.highlight .gs { font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.highlight .gt { color: #0044DD } /* Generic.Traceback */\n.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.highlight .kp { color: #008000 } /* Keyword.Pseudo */\n.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #B00040 } /* Keyword.Type */\n.highlight .m { color: #666666 } /* Literal.Number */\n.highlight .s { color: #BA2121 } /* Literal.String */\n.highlight .na { color: #7D9029 } /* Name.Attribute */\n.highlight .nb { color: #008000 } /* Name.Builtin */\n.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.highlight .no { color: #880000 } /* Name.Constant */\n.highlight .nd { color: #AA22FF } /* Name.Decorator */\n.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #0000FF } /* Name.Function */\n.highlight .nl { color: #A0A000 } /* Name.Label */\n.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.highlight .nv { color: #19177C } /* Name.Variable */\n.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.highlight .w { color: #bbbbbb } /* Text.Whitespace */\n.highlight .mb { color: #666666 } /* Literal.Number.Bin */\n.highlight .mf { color: #666666 } /* Literal.Number.Float */\n.highlight .mh { color: #666666 } /* Literal.Number.Hex */\n.highlight .mi { color: #666666 } /* Literal.Number.Integer */\n.highlight .mo { color: #666666 } /* Literal.Number.Oct */\n.highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n.highlight .sc { color: #BA2121 } /* Literal.String.Char */\n.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.highlight .sx { color: #008000 } /* Literal.String.Other */\n.highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n.highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n.highlight .ss { color: #19177C } /* Literal.String.Symbol */\n.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.highlight .fm { color: #0000FF } /* Name.Function.Magic */\n.highlight .vc { color: #19177C } /* Name.Variable.Class */\n.highlight .vg { color: #19177C } /* Name.Variable.Global */\n.highlight .vi { color: #19177C } /* Name.Variable.Instance */\n.highlight .vm { color: #19177C } /* Name.Variable.Magic */\n.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" }, "metadata": {}, "output_type": "display_data" }, { "data": { - "text/html": [ - "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"nf\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_img</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_2</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"n\">w_2</span><span class=\"p\">)</span>\n", - "<span class=\"p\">{</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22</span> <span class=\"o\">=</span> <span class=\"n\">_data_img</span> <span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"o\">*</span><span class=\"n\">_stride_img_2</span><span class=\"p\">;</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_0</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"n\">_stride_dst_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_01</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_1</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">_stride_dst_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">])</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]));</span>\n", - " <span class=\"p\">}</span>\n", - " <span class=\"p\">}</span>\n", - "<span class=\"p\">}</span>\n", - "</pre></div>\n" - ], - "text/plain": [ - "FUNC_PREFIX void kernel(double * RESTRICT _data_dst, double * RESTRICT const _data_img, int64_t const _size_dst_0, int64_t const _size_dst_1, int64_t const _stride_dst_0, int64_t const _stride_dst_1, int64_t const _stride_img_0, int64_t const _stride_img_1, int64_t const _stride_img_2, double w_2)\n", - "{\n", - " double * RESTRICT _data_img_22 = _data_img + 2*_stride_img_2;\n", - " for (int ctr_0 = 1; ctr_0 < _size_dst_0 - 1; ctr_0 += 1)\n", - " {\n", - " double * RESTRICT _data_dst_00 = _data_dst + _stride_dst_0*ctr_0;\n", - " double * RESTRICT _data_img_22_01 = _stride_img_0*ctr_0 + _stride_img_0 + _data_img_22;\n", - " double * RESTRICT _data_img_22_0m1 = _stride_img_0*ctr_0 - _stride_img_0 + _data_img_22;\n", - " for (int ctr_1 = 1; ctr_1 < _size_dst_1 - 1; ctr_1 += 1)\n", - " {\n", - " _data_dst_00[_stride_dst_1*ctr_1] = ((w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1])*(w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1]));\n", - " }\n", - " }\n", - "}" - ] + "text/plain": "FUNC_PREFIX void kernel(double * RESTRICT _data_dst, double * RESTRICT const _data_img, int64_t const _size_dst_0, int64_t const _size_dst_1, int64_t const _stride_dst_0, int64_t const _stride_dst_1, int64_t const _stride_img_0, int64_t const _stride_img_1, int64_t const _stride_img_2, double w_2)\n{\n double * RESTRICT _data_img_22 = _data_img + 2*_stride_img_2;\n for (int64_t ctr_0 = 1; ctr_0 < _size_dst_0 - 1; ctr_0 += 1)\n {\n double * RESTRICT _data_dst_00 = _data_dst + _stride_dst_0*ctr_0;\n double * RESTRICT _data_img_22_01 = _stride_img_0*ctr_0 + _stride_img_0 + _data_img_22;\n double * RESTRICT _data_img_22_0m1 = _stride_img_0*ctr_0 - _stride_img_0 + _data_img_22;\n for (int64_t ctr_1 = 1; ctr_1 < _size_dst_1 - 1; ctr_1 += 1)\n {\n _data_dst_00[_stride_dst_1*ctr_1] = ((w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1])*(w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1]));\n }\n }\n}", + "text/html": "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"n\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_img</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_2</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"n\">w_2</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22</span> <span class=\"o\">=</span> <span class=\"n\">_data_img</span> <span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"o\">*</span><span class=\"n\">_stride_img_2</span><span class=\"p\">;</span>\n <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_0</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n <span class=\"p\">{</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"n\">_stride_dst_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_01</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_1</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n <span class=\"p\">{</span>\n <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">_stride_dst_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">])</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]));</span>\n <span class=\"p\">}</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre></div>\n" }, "metadata": {}, "output_type": "display_data" @@ -1291,127 +804,16 @@ "outputs": [ { "data": { - "text/html": [ - "<style>.highlight .hll { background-color: #ffffcc }\n", - ".highlight { background: #f8f8f8; }\n", - ".highlight .c { color: #408080; font-style: italic } /* Comment */\n", - ".highlight .err { border: 1px solid #FF0000 } /* Error */\n", - ".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n", - ".highlight .o { color: #666666 } /* Operator */\n", - ".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n", - ".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n", - ".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n", - ".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n", - ".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n", - ".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n", - ".highlight .gd { color: #A00000 } /* Generic.Deleted */\n", - ".highlight .ge { font-style: italic } /* Generic.Emph */\n", - ".highlight .gr { color: #FF0000 } /* Generic.Error */\n", - ".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n", - ".highlight .gi { color: #00A000 } /* Generic.Inserted */\n", - ".highlight .go { color: #888888 } /* Generic.Output */\n", - ".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n", - ".highlight .gs { font-weight: bold } /* Generic.Strong */\n", - ".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n", - ".highlight .gt { color: #0044DD } /* Generic.Traceback */\n", - ".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n", - ".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n", - ".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n", - ".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n", - ".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n", - ".highlight .kt { color: #B00040 } /* Keyword.Type */\n", - ".highlight .m { color: #666666 } /* Literal.Number */\n", - ".highlight .s { color: #BA2121 } /* Literal.String */\n", - ".highlight .na { color: #7D9029 } /* Name.Attribute */\n", - ".highlight .nb { color: #008000 } /* Name.Builtin */\n", - ".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n", - ".highlight .no { color: #880000 } /* Name.Constant */\n", - ".highlight .nd { color: #AA22FF } /* Name.Decorator */\n", - ".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n", - ".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n", - ".highlight .nf { color: #0000FF } /* Name.Function */\n", - ".highlight .nl { color: #A0A000 } /* Name.Label */\n", - ".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n", - ".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n", - ".highlight .nv { color: #19177C } /* Name.Variable */\n", - ".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n", - ".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n", - ".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n", - ".highlight .mf { color: #666666 } /* Literal.Number.Float */\n", - ".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n", - ".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n", - ".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n", - ".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n", - ".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n", - ".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n", - ".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n", - ".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n", - ".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n", - ".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n", - ".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n", - ".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n", - ".highlight .sx { color: #008000 } /* Literal.String.Other */\n", - ".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n", - ".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n", - ".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n", - ".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n", - ".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n", - ".highlight .vc { color: #19177C } /* Name.Variable.Class */\n", - ".highlight .vg { color: #19177C } /* Name.Variable.Global */\n", - ".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n", - ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", - ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] + "text/plain": "<IPython.core.display.HTML object>", + "text/html": "<style>pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.highlight .hll { background-color: #ffffcc }\n.highlight { background: #f8f8f8; }\n.highlight .c { color: #408080; font-style: italic } /* Comment */\n.highlight .err { border: 1px solid #FF0000 } /* Error */\n.highlight .k { color: #008000; font-weight: bold } /* Keyword */\n.highlight .o { color: #666666 } /* Operator */\n.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #A00000 } /* Generic.Deleted */\n.highlight .ge { font-style: italic } /* Generic.Emph */\n.highlight .gr { color: #FF0000 } /* Generic.Error */\n.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.highlight .gi { color: #00A000 } /* Generic.Inserted */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.highlight .gs { font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.highlight .gt { color: #0044DD } /* Generic.Traceback */\n.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.highlight .kp { color: #008000 } /* Keyword.Pseudo */\n.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #B00040 } /* Keyword.Type */\n.highlight .m { color: #666666 } /* Literal.Number */\n.highlight .s { color: #BA2121 } /* Literal.String */\n.highlight .na { color: #7D9029 } /* Name.Attribute */\n.highlight .nb { color: #008000 } /* Name.Builtin */\n.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.highlight .no { color: #880000 } /* Name.Constant */\n.highlight .nd { color: #AA22FF } /* Name.Decorator */\n.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #0000FF } /* Name.Function */\n.highlight .nl { color: #A0A000 } /* Name.Label */\n.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.highlight .nv { color: #19177C } /* Name.Variable */\n.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.highlight .w { color: #bbbbbb } /* Text.Whitespace */\n.highlight .mb { color: #666666 } /* Literal.Number.Bin */\n.highlight .mf { color: #666666 } /* Literal.Number.Float */\n.highlight .mh { color: #666666 } /* Literal.Number.Hex */\n.highlight .mi { color: #666666 } /* Literal.Number.Integer */\n.highlight .mo { color: #666666 } /* Literal.Number.Oct */\n.highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n.highlight .sc { color: #BA2121 } /* Literal.String.Char */\n.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.highlight .sx { color: #008000 } /* Literal.String.Other */\n.highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n.highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n.highlight .ss { color: #19177C } /* Literal.String.Symbol */\n.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.highlight .fm { color: #0000FF } /* Name.Function.Magic */\n.highlight .vc { color: #19177C } /* Name.Variable.Class */\n.highlight .vg { color: #19177C } /* Name.Variable.Global */\n.highlight .vi { color: #19177C } /* Name.Variable.Instance */\n.highlight .vm { color: #19177C } /* Name.Variable.Magic */\n.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" }, "metadata": {}, "output_type": "display_data" }, { "data": { - "text/html": [ - "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"nf\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_img</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_2</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"n\">w_2</span><span class=\"p\">)</span>\n", - "<span class=\"p\">{</span>\n", - " <span class=\"cp\">#pragma omp parallel num_threads(2)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22</span> <span class=\"o\">=</span> <span class=\"n\">_data_img</span> <span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"o\">*</span><span class=\"n\">_stride_img_2</span><span class=\"p\">;</span>\n", - " <span class=\"cp\">#pragma omp for schedule(static)</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_0</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"n\">_stride_dst_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_01</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_1</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">_stride_dst_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">])</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]));</span>\n", - " <span class=\"p\">}</span>\n", - " <span class=\"p\">}</span>\n", - " <span class=\"p\">}</span>\n", - "<span class=\"p\">}</span>\n", - "</pre></div>\n" - ], - "text/plain": [ - "FUNC_PREFIX void kernel(double * RESTRICT _data_dst, double * RESTRICT const _data_img, int64_t const _size_dst_0, int64_t const _size_dst_1, int64_t const _stride_dst_0, int64_t const _stride_dst_1, int64_t const _stride_img_0, int64_t const _stride_img_1, int64_t const _stride_img_2, double w_2)\n", - "{\n", - " #pragma omp parallel num_threads(2)\n", - " {\n", - " double * RESTRICT _data_img_22 = _data_img + 2*_stride_img_2;\n", - " #pragma omp for schedule(static)\n", - " for (int ctr_0 = 1; ctr_0 < _size_dst_0 - 1; ctr_0 += 1)\n", - " {\n", - " double * RESTRICT _data_dst_00 = _data_dst + _stride_dst_0*ctr_0;\n", - " double * RESTRICT _data_img_22_01 = _stride_img_0*ctr_0 + _stride_img_0 + _data_img_22;\n", - " double * RESTRICT _data_img_22_0m1 = _stride_img_0*ctr_0 - _stride_img_0 + _data_img_22;\n", - " for (int ctr_1 = 1; ctr_1 < _size_dst_1 - 1; ctr_1 += 1)\n", - " {\n", - " _data_dst_00[_stride_dst_1*ctr_1] = ((w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1])*(w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1]));\n", - " }\n", - " }\n", - " }\n", - "}" - ] + "text/plain": "FUNC_PREFIX void kernel(double * RESTRICT _data_dst, double * RESTRICT const _data_img, int64_t const _size_dst_0, int64_t const _size_dst_1, int64_t const _stride_dst_0, int64_t const _stride_dst_1, int64_t const _stride_img_0, int64_t const _stride_img_1, int64_t const _stride_img_2, double w_2)\n{\n #pragma omp parallel num_threads(2)\n {\n double * RESTRICT _data_img_22 = _data_img + 2*_stride_img_2;\n #pragma omp for schedule(static)\n for (int64_t ctr_0 = 1; ctr_0 < _size_dst_0 - 1; ctr_0 += 1)\n {\n double * RESTRICT _data_dst_00 = _data_dst + _stride_dst_0*ctr_0;\n double * RESTRICT _data_img_22_01 = _stride_img_0*ctr_0 + _stride_img_0 + _data_img_22;\n double * RESTRICT _data_img_22_0m1 = _stride_img_0*ctr_0 - _stride_img_0 + _data_img_22;\n for (int64_t ctr_1 = 1; ctr_1 < _size_dst_1 - 1; ctr_1 += 1)\n {\n _data_dst_00[_stride_dst_1*ctr_1] = ((w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1])*(w_2*_data_img_22_01[_stride_img_1*ctr_1] - w_2*_data_img_22_0m1[_stride_img_1*ctr_1] - 0.5*_data_img_22_01[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 + _stride_img_1] - 0.5*_data_img_22_0m1[_stride_img_1*ctr_1 - _stride_img_1] + 0.5*_data_img_22_01[_stride_img_1*ctr_1 - _stride_img_1]));\n }\n }\n }\n}", + "text/html": "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"n\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_img</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_img_2</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"n\">w_2</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n <span class=\"cp\">#pragma omp parallel num_threads(2)</span>\n <span class=\"p\">{</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22</span> <span class=\"o\">=</span> <span class=\"n\">_data_img</span> <span class=\"o\">+</span> <span class=\"mi\">2</span><span class=\"o\">*</span><span class=\"n\">_stride_img_2</span><span class=\"p\">;</span>\n <span class=\"cp\">#pragma omp for schedule(static)</span>\n <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_0</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n <span class=\"p\">{</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"n\">_stride_dst_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_01</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_img_22_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_stride_img_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_0</span> <span class=\"o\">+</span> <span class=\"n\">_data_img_22</span><span class=\"p\">;</span>\n <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_1</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n <span class=\"p\">{</span>\n <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">_stride_dst_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">((</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">])</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">w_2</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.5</span><span class=\"o\">*</span><span class=\"n\">_data_img_22_01</span><span class=\"p\">[</span><span class=\"n\">_stride_img_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_img_1</span><span class=\"p\">]));</span>\n <span class=\"p\">}</span>\n <span class=\"p\">}</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre></div>\n" }, "metadata": {}, "output_type": "display_data" @@ -1430,9 +832,7 @@ "outputs": [ { "data": { - "text/plain": [ - "False" - ] + "text/plain": "False" }, "execution_count": 35, "metadata": {}, @@ -1463,119 +863,16 @@ "outputs": [ { "data": { - "text/html": [ - "<style>.highlight .hll { background-color: #ffffcc }\n", - ".highlight { background: #f8f8f8; }\n", - ".highlight .c { color: #408080; font-style: italic } /* Comment */\n", - ".highlight .err { border: 1px solid #FF0000 } /* Error */\n", - ".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n", - ".highlight .o { color: #666666 } /* Operator */\n", - ".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n", - ".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n", - ".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n", - ".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n", - ".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n", - ".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n", - ".highlight .gd { color: #A00000 } /* Generic.Deleted */\n", - ".highlight .ge { font-style: italic } /* Generic.Emph */\n", - ".highlight .gr { color: #FF0000 } /* Generic.Error */\n", - ".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n", - ".highlight .gi { color: #00A000 } /* Generic.Inserted */\n", - ".highlight .go { color: #888888 } /* Generic.Output */\n", - ".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n", - ".highlight .gs { font-weight: bold } /* Generic.Strong */\n", - ".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n", - ".highlight .gt { color: #0044DD } /* Generic.Traceback */\n", - ".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n", - ".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n", - ".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n", - ".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n", - ".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n", - ".highlight .kt { color: #B00040 } /* Keyword.Type */\n", - ".highlight .m { color: #666666 } /* Literal.Number */\n", - ".highlight .s { color: #BA2121 } /* Literal.String */\n", - ".highlight .na { color: #7D9029 } /* Name.Attribute */\n", - ".highlight .nb { color: #008000 } /* Name.Builtin */\n", - ".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n", - ".highlight .no { color: #880000 } /* Name.Constant */\n", - ".highlight .nd { color: #AA22FF } /* Name.Decorator */\n", - ".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n", - ".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n", - ".highlight .nf { color: #0000FF } /* Name.Function */\n", - ".highlight .nl { color: #A0A000 } /* Name.Label */\n", - ".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n", - ".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n", - ".highlight .nv { color: #19177C } /* Name.Variable */\n", - ".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n", - ".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n", - ".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n", - ".highlight .mf { color: #666666 } /* Literal.Number.Float */\n", - ".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n", - ".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n", - ".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n", - ".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n", - ".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n", - ".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n", - ".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n", - ".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n", - ".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n", - ".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n", - ".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n", - ".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n", - ".highlight .sx { color: #008000 } /* Literal.String.Other */\n", - ".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n", - ".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n", - ".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n", - ".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n", - ".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n", - ".highlight .vc { color: #19177C } /* Name.Variable.Class */\n", - ".highlight .vg { color: #19177C } /* Name.Variable.Global */\n", - ".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n", - ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", - ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] + "text/plain": "<IPython.core.display.HTML object>", + "text/html": "<style>pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.highlight .hll { background-color: #ffffcc }\n.highlight { background: #f8f8f8; }\n.highlight .c { color: #408080; font-style: italic } /* Comment */\n.highlight .err { border: 1px solid #FF0000 } /* Error */\n.highlight .k { color: #008000; font-weight: bold } /* Keyword */\n.highlight .o { color: #666666 } /* Operator */\n.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #A00000 } /* Generic.Deleted */\n.highlight .ge { font-style: italic } /* Generic.Emph */\n.highlight .gr { color: #FF0000 } /* Generic.Error */\n.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.highlight .gi { color: #00A000 } /* Generic.Inserted */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.highlight .gs { font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.highlight .gt { color: #0044DD } /* Generic.Traceback */\n.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.highlight .kp { color: #008000 } /* Keyword.Pseudo */\n.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #B00040 } /* Keyword.Type */\n.highlight .m { color: #666666 } /* Literal.Number */\n.highlight .s { color: #BA2121 } /* Literal.String */\n.highlight .na { color: #7D9029 } /* Name.Attribute */\n.highlight .nb { color: #008000 } /* Name.Builtin */\n.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.highlight .no { color: #880000 } /* Name.Constant */\n.highlight .nd { color: #AA22FF } /* Name.Decorator */\n.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #0000FF } /* Name.Function */\n.highlight .nl { color: #A0A000 } /* Name.Label */\n.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.highlight .nv { color: #19177C } /* Name.Variable */\n.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.highlight .w { color: #bbbbbb } /* Text.Whitespace */\n.highlight .mb { color: #666666 } /* Literal.Number.Bin */\n.highlight .mf { color: #666666 } /* Literal.Number.Float */\n.highlight .mh { color: #666666 } /* Literal.Number.Hex */\n.highlight .mi { color: #666666 } /* Literal.Number.Integer */\n.highlight .mo { color: #666666 } /* Literal.Number.Oct */\n.highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n.highlight .sc { color: #BA2121 } /* Literal.String.Char */\n.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.highlight .sx { color: #008000 } /* Literal.String.Other */\n.highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n.highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n.highlight .ss { color: #19177C } /* Literal.String.Symbol */\n.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.highlight .fm { color: #0000FF } /* Name.Function.Magic */\n.highlight .vc { color: #19177C } /* Name.Variable.Class */\n.highlight .vg { color: #19177C } /* Name.Variable.Global */\n.highlight .vi { color: #19177C } /* Name.Variable.Instance */\n.highlight .vm { color: #19177C } /* Name.Variable.Magic */\n.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" }, "metadata": {}, "output_type": "display_data" }, { "data": { - "text/html": [ - "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"nf\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_I</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">)</span>\n", - "<span class=\"p\">{</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"mi\">81</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"mi\">290</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_21_01</span> <span class=\"o\">=</span> <span class=\"n\">_data_I_21</span> <span class=\"o\">+</span> <span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">1160</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_21_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_data_I_21</span> <span class=\"o\">+</span> <span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">1160</span><span class=\"p\">;</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"mi\">289</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_21_0m1</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_21_01</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_21_01</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">_data_I_21_01</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_21_0m1</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_21_0m1</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"mi\">4</span><span class=\"p\">];</span>\n", - " <span class=\"p\">}</span>\n", - " <span class=\"p\">}</span>\n", - "<span class=\"p\">}</span>\n", - "</pre></div>\n" - ], - "text/plain": [ - "FUNC_PREFIX void kernel(double * RESTRICT const _data_I, double * RESTRICT _data_dst)\n", - "{\n", - " double * RESTRICT _data_I_21 = _data_I + 1;\n", - " for (int ctr_0 = 1; ctr_0 < 81; ctr_0 += 1)\n", - " {\n", - " double * RESTRICT _data_dst_00 = _data_dst + 290*ctr_0;\n", - " double * RESTRICT _data_I_21_01 = _data_I_21 + 1160*ctr_0 + 1160;\n", - " double * RESTRICT _data_I_21_0m1 = _data_I_21 + 1160*ctr_0 - 1160;\n", - " for (int ctr_1 = 1; ctr_1 < 289; ctr_1 += 1)\n", - " {\n", - " _data_dst_00[ctr_1] = -2.0*_data_I_21_0m1[4*ctr_1] + 2.0*_data_I_21_01[4*ctr_1] - _data_I_21_01[4*ctr_1 + 4] + _data_I_21_01[4*ctr_1 - 4] - _data_I_21_0m1[4*ctr_1 + 4] - _data_I_21_0m1[4*ctr_1 - 4];\n", - " }\n", - " }\n", - "}" - ] + "text/plain": "FUNC_PREFIX void kernel(double * RESTRICT const _data_I, double * RESTRICT _data_dst)\n{\n double * RESTRICT _data_I_21 = _data_I + 1;\n for (int64_t ctr_0 = 1; ctr_0 < 202; ctr_0 += 1)\n {\n double * RESTRICT _data_dst_00 = _data_dst + 601*ctr_0;\n double * RESTRICT _data_I_21_01 = _data_I_21 + 2404*ctr_0 + 2404;\n double * RESTRICT _data_I_21_0m1 = _data_I_21 + 2404*ctr_0 - 2404;\n for (int64_t ctr_1 = 1; ctr_1 < 600; ctr_1 += 1)\n {\n _data_dst_00[ctr_1] = -2.0*_data_I_21_0m1[4*ctr_1] + 2.0*_data_I_21_01[4*ctr_1] - _data_I_21_01[4*ctr_1 + 4] + _data_I_21_01[4*ctr_1 - 4] - _data_I_21_0m1[4*ctr_1 + 4] - _data_I_21_0m1[4*ctr_1 - 4];\n }\n }\n}", + "text/html": "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"n\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_I</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"mi\">202</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n <span class=\"p\">{</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"mi\">601</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_21_01</span> <span class=\"o\">=</span> <span class=\"n\">_data_I_21</span> <span class=\"o\">+</span> <span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">2404</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_21_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_data_I_21</span> <span class=\"o\">+</span> <span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">2404</span><span class=\"p\">;</span>\n <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"mi\">600</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n <span class=\"p\">{</span>\n <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">-2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_21_0m1</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_21_01</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_21_01</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">_data_I_21_01</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_21_0m1</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_21_0m1</span><span class=\"p\">[</span><span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"mi\">4</span><span class=\"p\">];</span>\n <span class=\"p\">}</span>\n <span class=\"p\">}</span>\n<span class=\"p\">}</span>\n</pre></div>\n" }, "metadata": {}, "output_type": "display_data" @@ -1614,7 +911,7 @@ "metadata": {}, "outputs": [], "source": [ - "gpu_ast = create_kernel(update_rule, target='gpu', gpu_indexing=ps.gpucuda.indexing.BlockIndexing, \n", + "gpu_ast = create_kernel(update_rule, target=ps.Target.GPU, gpu_indexing=ps.gpucuda.indexing.BlockIndexing,\n", " gpu_indexing_params={'blockSize': (8,8,4)})" ] }, @@ -1625,117 +922,16 @@ "outputs": [ { "data": { - "text/html": [ - "<style>.highlight .hll { background-color: #ffffcc }\n", - ".highlight { background: #f8f8f8; }\n", - ".highlight .c { color: #408080; font-style: italic } /* Comment */\n", - ".highlight .err { border: 1px solid #FF0000 } /* Error */\n", - ".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n", - ".highlight .o { color: #666666 } /* Operator */\n", - ".highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n", - ".highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n", - ".highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n", - ".highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n", - ".highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n", - ".highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n", - ".highlight .gd { color: #A00000 } /* Generic.Deleted */\n", - ".highlight .ge { font-style: italic } /* Generic.Emph */\n", - ".highlight .gr { color: #FF0000 } /* Generic.Error */\n", - ".highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n", - ".highlight .gi { color: #00A000 } /* Generic.Inserted */\n", - ".highlight .go { color: #888888 } /* Generic.Output */\n", - ".highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n", - ".highlight .gs { font-weight: bold } /* Generic.Strong */\n", - ".highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n", - ".highlight .gt { color: #0044DD } /* Generic.Traceback */\n", - ".highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n", - ".highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n", - ".highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n", - ".highlight .kp { color: #008000 } /* Keyword.Pseudo */\n", - ".highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n", - ".highlight .kt { color: #B00040 } /* Keyword.Type */\n", - ".highlight .m { color: #666666 } /* Literal.Number */\n", - ".highlight .s { color: #BA2121 } /* Literal.String */\n", - ".highlight .na { color: #7D9029 } /* Name.Attribute */\n", - ".highlight .nb { color: #008000 } /* Name.Builtin */\n", - ".highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n", - ".highlight .no { color: #880000 } /* Name.Constant */\n", - ".highlight .nd { color: #AA22FF } /* Name.Decorator */\n", - ".highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n", - ".highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n", - ".highlight .nf { color: #0000FF } /* Name.Function */\n", - ".highlight .nl { color: #A0A000 } /* Name.Label */\n", - ".highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n", - ".highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n", - ".highlight .nv { color: #19177C } /* Name.Variable */\n", - ".highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n", - ".highlight .w { color: #bbbbbb } /* Text.Whitespace */\n", - ".highlight .mb { color: #666666 } /* Literal.Number.Bin */\n", - ".highlight .mf { color: #666666 } /* Literal.Number.Float */\n", - ".highlight .mh { color: #666666 } /* Literal.Number.Hex */\n", - ".highlight .mi { color: #666666 } /* Literal.Number.Integer */\n", - ".highlight .mo { color: #666666 } /* Literal.Number.Oct */\n", - ".highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n", - ".highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n", - ".highlight .sc { color: #BA2121 } /* Literal.String.Char */\n", - ".highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n", - ".highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n", - ".highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n", - ".highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n", - ".highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n", - ".highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n", - ".highlight .sx { color: #008000 } /* Literal.String.Other */\n", - ".highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n", - ".highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n", - ".highlight .ss { color: #19177C } /* Literal.String.Symbol */\n", - ".highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n", - ".highlight .fm { color: #0000FF } /* Name.Function.Magic */\n", - ".highlight .vc { color: #19177C } /* Name.Variable.Class */\n", - ".highlight .vg { color: #19177C } /* Name.Variable.Global */\n", - ".highlight .vi { color: #19177C } /* Name.Variable.Instance */\n", - ".highlight .vm { color: #19177C } /* Name.Variable.Magic */\n", - ".highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" - ], - "text/plain": [ - "<IPython.core.display.HTML object>" - ] + "text/plain": "<IPython.core.display.HTML object>", + "text/html": "<style>pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.highlight .hll { background-color: #ffffcc }\n.highlight { background: #f8f8f8; }\n.highlight .c { color: #408080; font-style: italic } /* Comment */\n.highlight .err { border: 1px solid #FF0000 } /* Error */\n.highlight .k { color: #008000; font-weight: bold } /* Keyword */\n.highlight .o { color: #666666 } /* Operator */\n.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #BC7A00 } /* Comment.Preproc */\n.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #A00000 } /* Generic.Deleted */\n.highlight .ge { font-style: italic } /* Generic.Emph */\n.highlight .gr { color: #FF0000 } /* Generic.Error */\n.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.highlight .gi { color: #00A000 } /* Generic.Inserted */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.highlight .gs { font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.highlight .gt { color: #0044DD } /* Generic.Traceback */\n.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.highlight .kp { color: #008000 } /* Keyword.Pseudo */\n.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #B00040 } /* Keyword.Type */\n.highlight .m { color: #666666 } /* Literal.Number */\n.highlight .s { color: #BA2121 } /* Literal.String */\n.highlight .na { color: #7D9029 } /* Name.Attribute */\n.highlight .nb { color: #008000 } /* Name.Builtin */\n.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n.highlight .no { color: #880000 } /* Name.Constant */\n.highlight .nd { color: #AA22FF } /* Name.Decorator */\n.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */\n.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #0000FF } /* Name.Function */\n.highlight .nl { color: #A0A000 } /* Name.Label */\n.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.highlight .nv { color: #19177C } /* Name.Variable */\n.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n.highlight .w { color: #bbbbbb } /* Text.Whitespace */\n.highlight .mb { color: #666666 } /* Literal.Number.Bin */\n.highlight .mf { color: #666666 } /* Literal.Number.Float */\n.highlight .mh { color: #666666 } /* Literal.Number.Hex */\n.highlight .mi { color: #666666 } /* Literal.Number.Integer */\n.highlight .mo { color: #666666 } /* Literal.Number.Oct */\n.highlight .sa { color: #BA2121 } /* Literal.String.Affix */\n.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */\n.highlight .sc { color: #BA2121 } /* Literal.String.Char */\n.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.highlight .s2 { color: #BA2121 } /* Literal.String.Double */\n.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n.highlight .sx { color: #008000 } /* Literal.String.Other */\n.highlight .sr { color: #BB6688 } /* Literal.String.Regex */\n.highlight .s1 { color: #BA2121 } /* Literal.String.Single */\n.highlight .ss { color: #19177C } /* Literal.String.Symbol */\n.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.highlight .fm { color: #0000FF } /* Name.Function.Magic */\n.highlight .vc { color: #19177C } /* Name.Variable.Class */\n.highlight .vg { color: #19177C } /* Name.Variable.Global */\n.highlight .vi { color: #19177C } /* Name.Variable.Instance */\n.highlight .vm { color: #19177C } /* Name.Variable.Magic */\n.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */</style>" }, "metadata": {}, "output_type": "display_data" }, { "data": { - "text/html": [ - "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"nf\">__launch_bounds__</span><span class=\"p\">(</span><span class=\"mi\">256</span><span class=\"p\">)</span> <span class=\"kt\">void</span> <span class=\"n\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_I</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">)</span>\n", - "<span class=\"p\">{</span>\n", - " <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\"><</span> <span class=\"mi\">81</span> <span class=\"o\">&&</span> <span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\"><</span> <span class=\"mi\">289</span><span class=\"p\">)</span>\n", - " <span class=\"p\">{</span>\n", - " <span class=\"k\">const</span> <span class=\"kt\">int64_t</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n", - " <span class=\"k\">const</span> <span class=\"kt\">int64_t</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_10</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"n\">ctr_1</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_11_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_1m1_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"mi\">3</span><span class=\"p\">;</span>\n", - " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_10_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n", - " <span class=\"n\">_data_dst_10</span><span class=\"p\">[</span><span class=\"mi\">290</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_10_21</span><span class=\"p\">[</span><span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">1160</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_10_21</span><span class=\"p\">[</span><span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">1160</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_11_21</span><span class=\"p\">[</span><span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">1160</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_11_21</span><span class=\"p\">[</span><span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">1160</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">_data_I_1m1_21</span><span class=\"p\">[</span><span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">1160</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_1m1_21</span><span class=\"p\">[</span><span class=\"mi\">1160</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">1160</span><span class=\"p\">];</span>\n", - " <span class=\"p\">}</span> \n", - "<span class=\"p\">}</span>\n", - "</pre></div>\n" - ], - "text/plain": [ - "FUNC_PREFIX __launch_bounds__(256) void kernel(double * RESTRICT const _data_I, double * RESTRICT _data_dst)\n", - "{\n", - " if (blockDim.x*blockIdx.x + threadIdx.x + 1 < 81 && blockDim.y*blockIdx.y + threadIdx.y + 1 < 289)\n", - " {\n", - " const int64_t ctr_0 = blockDim.x*blockIdx.x + threadIdx.x + 1;\n", - " const int64_t ctr_1 = blockDim.y*blockIdx.y + threadIdx.y + 1;\n", - " double * RESTRICT _data_dst_10 = _data_dst + ctr_1;\n", - " double * RESTRICT _data_I_11_21 = _data_I + 4*ctr_1 + 5;\n", - " double * RESTRICT _data_I_1m1_21 = _data_I + 4*ctr_1 - 3;\n", - " double * RESTRICT _data_I_10_21 = _data_I + 4*ctr_1 + 1;\n", - " _data_dst_10[290*ctr_0] = -2.0*_data_I_10_21[1160*ctr_0 - 1160] + 2.0*_data_I_10_21[1160*ctr_0 + 1160] - _data_I_11_21[1160*ctr_0 + 1160] - _data_I_11_21[1160*ctr_0 - 1160] + _data_I_1m1_21[1160*ctr_0 + 1160] - _data_I_1m1_21[1160*ctr_0 - 1160];\n", - " } \n", - "}" - ] + "text/plain": "FUNC_PREFIX __launch_bounds__(256) void kernel(double * RESTRICT const _data_I, double * RESTRICT _data_dst)\n{\n if (blockDim.x*blockIdx.x + threadIdx.x + 1 < 202 && blockDim.y*blockIdx.y + threadIdx.y + 1 < 600)\n {\n const int64_t ctr_0 = blockDim.x*blockIdx.x + threadIdx.x + 1;\n const int64_t ctr_1 = blockDim.y*blockIdx.y + threadIdx.y + 1;\n double * RESTRICT _data_dst_10 = _data_dst + ctr_1;\n double * RESTRICT _data_I_11_21 = _data_I + 4*ctr_1 + 5;\n double * RESTRICT _data_I_1m1_21 = _data_I + 4*ctr_1 - 3;\n double * RESTRICT _data_I_10_21 = _data_I + 4*ctr_1 + 1;\n _data_dst_10[601*ctr_0] = -2.0*_data_I_10_21[2404*ctr_0 - 2404] + 2.0*_data_I_10_21[2404*ctr_0 + 2404] - _data_I_11_21[2404*ctr_0 + 2404] - _data_I_11_21[2404*ctr_0 - 2404] + _data_I_1m1_21[2404*ctr_0 + 2404] - _data_I_1m1_21[2404*ctr_0 - 2404];\n } \n}", + "text/html": "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"nf\">__launch_bounds__</span><span class=\"p\">(</span><span class=\"mi\">256</span><span class=\"p\">)</span> <span class=\"kt\">void</span> <span class=\"n\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_I</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">)</span>\n<span class=\"p\">{</span>\n <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\"><</span> <span class=\"mi\">202</span> <span class=\"o\">&&</span> <span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"mi\">1</span> <span class=\"o\"><</span> <span class=\"mi\">600</span><span class=\"p\">)</span>\n <span class=\"p\">{</span>\n <span class=\"k\">const</span> <span class=\"kt\">int64_t</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">x</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n <span class=\"k\">const</span> <span class=\"kt\">int64_t</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"n\">blockDim</span><span class=\"p\">.</span><span class=\"n\">y</span><span class=\"o\">*</span><span class=\"n\">blockIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"n\">threadIdx</span><span class=\"p\">.</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_10</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"n\">ctr_1</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_11_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">5</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_1m1_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"mi\">3</span><span class=\"p\">;</span>\n <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_I_10_21</span> <span class=\"o\">=</span> <span class=\"n\">_data_I</span> <span class=\"o\">+</span> <span class=\"mi\">4</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">;</span>\n <span class=\"n\">_data_dst_10</span><span class=\"p\">[</span><span class=\"mi\">601</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">-2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_10_21</span><span class=\"p\">[</span><span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">2404</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">_data_I_10_21</span><span class=\"p\">[</span><span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">2404</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_11_21</span><span class=\"p\">[</span><span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">2404</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_11_21</span><span class=\"p\">[</span><span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">2404</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">_data_I_1m1_21</span><span class=\"p\">[</span><span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">2404</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">_data_I_1m1_21</span><span class=\"p\">[</span><span class=\"mi\">2404</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">2404</span><span class=\"p\">];</span>\n <span class=\"p\">}</span> \n<span class=\"p\">}</span>\n</pre></div>\n" }, "metadata": {}, "output_type": "display_data" @@ -1763,9 +959,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.9.2" } }, "nbformat": 4, - "nbformat_minor": 2 -} + "nbformat_minor": 4 +} \ No newline at end of file diff --git a/doc/notebooks/03_tutorial_datahandling.ipynb b/doc/notebooks/03_tutorial_datahandling.ipynb index 522bf3e34253e82c75e1e2f46aa099b3b2cc42fc..8fd475446abef8de78b417535315ece25a323d0c 100644 --- a/doc/notebooks/03_tutorial_datahandling.ipynb +++ b/doc/notebooks/03_tutorial_datahandling.ipynb @@ -6,6 +6,7 @@ "metadata": {}, "outputs": [], "source": [ + "import psutil\n", "from mpl_toolkits.mplot3d import Axes3D\n", "from matplotlib import pyplot, cm\n", "from pystencils.session import *\n", @@ -120,8 +121,13 @@ { "data": { "text/html": [ - "<style>.highlight .hll { background-color: #ffffcc }\n", - ".highlight { background: #f8f8f8; }\n", + "<style>pre { line-height: 125%; }\n", + "td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n", + "span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n", + "td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n", + "span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n", + ".highlight .hll { background-color: #ffffcc }\n", + ".highlight { background: #f8f8f8; }\n", ".highlight .c { color: #408080; font-style: italic } /* Comment */\n", ".highlight .err { border: 1px solid #FF0000 } /* Error */\n", ".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n", @@ -200,15 +206,15 @@ { "data": { "text/html": [ - "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"nf\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_src</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_src_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_src_1</span><span class=\"p\">)</span>\n", + "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"n\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_src</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_size_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_dst_1</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_src_0</span><span class=\"p\">,</span> <span class=\"kt\">int64_t</span> <span class=\"k\">const</span> <span class=\"n\">_stride_src_1</span><span class=\"p\">)</span>\n", "<span class=\"p\">{</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_0</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", + " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_0</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", " <span class=\"p\">{</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"n\">_stride_dst_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_src_01</span> <span class=\"o\">=</span> <span class=\"n\">_data_src</span> <span class=\"o\">+</span> <span class=\"n\">_stride_src_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"n\">_stride_src_0</span><span class=\"p\">;</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_src_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_src</span> <span class=\"o\">+</span> <span class=\"n\">_stride_src_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_src_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_data_src</span> <span class=\"o\">+</span> <span class=\"n\">_stride_src_0</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"n\">_stride_src_0</span><span class=\"p\">;</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_1</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", + " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"n\">_size_dst_1</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", " <span class=\"p\">{</span>\n", " <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">_stride_dst_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_00</span><span class=\"p\">[</span><span class=\"n\">_stride_src_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"n\">_stride_src_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_00</span><span class=\"p\">[</span><span class=\"n\">_stride_src_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"n\">_stride_src_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_01</span><span class=\"p\">[</span><span class=\"n\">_stride_src_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_0m1</span><span class=\"p\">[</span><span class=\"n\">_stride_src_1</span><span class=\"o\">*</span><span class=\"n\">ctr_1</span><span class=\"p\">];</span>\n", " <span class=\"p\">}</span>\n", @@ -219,13 +225,13 @@ "text/plain": [ "FUNC_PREFIX void kernel(double * RESTRICT _data_dst, double * RESTRICT const _data_src, int64_t const _size_dst_0, int64_t const _size_dst_1, int64_t const _stride_dst_0, int64_t const _stride_dst_1, int64_t const _stride_src_0, int64_t const _stride_src_1)\n", "{\n", - " for (int ctr_0 = 1; ctr_0 < _size_dst_0 - 1; ctr_0 += 1)\n", + " for (int64_t ctr_0 = 1; ctr_0 < _size_dst_0 - 1; ctr_0 += 1)\n", " {\n", " double * RESTRICT _data_dst_00 = _data_dst + _stride_dst_0*ctr_0;\n", " double * RESTRICT _data_src_01 = _data_src + _stride_src_0*ctr_0 + _stride_src_0;\n", " double * RESTRICT _data_src_00 = _data_src + _stride_src_0*ctr_0;\n", " double * RESTRICT _data_src_0m1 = _data_src + _stride_src_0*ctr_0 - _stride_src_0;\n", - " for (int ctr_1 = 1; ctr_1 < _size_dst_1 - 1; ctr_1 += 1)\n", + " for (int64_t ctr_1 = 1; ctr_1 < _size_dst_1 - 1; ctr_1 += 1)\n", " {\n", " _data_dst_00[_stride_dst_1*ctr_1] = 0.25*_data_src_00[_stride_src_1*ctr_1 + _stride_src_1] + 0.25*_data_src_00[_stride_src_1*ctr_1 - _stride_src_1] + 0.25*_data_src_01[_stride_src_1*ctr_1] + 0.25*_data_src_0m1[_stride_src_1*ctr_1];\n", " }\n", @@ -298,8 +304,13 @@ { "data": { "text/html": [ - "<style>.highlight .hll { background-color: #ffffcc }\n", - ".highlight { background: #f8f8f8; }\n", + "<style>pre { line-height: 125%; }\n", + "td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n", + "span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\n", + "td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n", + "span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n", + ".highlight .hll { background-color: #ffffcc }\n", + ".highlight { background: #f8f8f8; }\n", ".highlight .c { color: #408080; font-style: italic } /* Comment */\n", ".highlight .err { border: 1px solid #FF0000 } /* Error */\n", ".highlight .k { color: #008000; font-weight: bold } /* Keyword */\n", @@ -378,15 +389,15 @@ { "data": { "text/html": [ - "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"nf\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_src</span><span class=\"p\">)</span>\n", + "<div class=\"highlight\"><pre><span></span><span class=\"n\">FUNC_PREFIX</span> <span class=\"kt\">void</span> <span class=\"n\">kernel</span><span class=\"p\">(</span><span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst</span><span class=\"p\">,</span> <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"k\">const</span> <span class=\"n\">_data_src</span><span class=\"p\">)</span>\n", "<span class=\"p\">{</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"mi\">29</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", + " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_0</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\"><</span> <span class=\"mi\">29</span><span class=\"p\">;</span> <span class=\"n\">ctr_0</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", " <span class=\"p\">{</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_dst_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_dst</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_src_01</span> <span class=\"o\">=</span> <span class=\"n\">_data_src</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"p\">;</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_src_00</span> <span class=\"o\">=</span> <span class=\"n\">_data_src</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span><span class=\"p\">;</span>\n", " <span class=\"kt\">double</span> <span class=\"o\">*</span> <span class=\"n\">RESTRICT</span> <span class=\"n\">_data_src_0m1</span> <span class=\"o\">=</span> <span class=\"n\">_data_src</span> <span class=\"o\">+</span> <span class=\"mi\">30</span><span class=\"o\">*</span><span class=\"n\">ctr_0</span> <span class=\"o\">-</span> <span class=\"mi\">30</span><span class=\"p\">;</span>\n", - " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"mi\">29</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", + " <span class=\"k\">for</span> <span class=\"p\">(</span><span class=\"kt\">int64_t</span> <span class=\"n\">ctr_1</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\"><</span> <span class=\"mi\">29</span><span class=\"p\">;</span> <span class=\"n\">ctr_1</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n", " <span class=\"p\">{</span>\n", " <span class=\"n\">_data_dst_00</span><span class=\"p\">[</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_00</span><span class=\"p\">[</span><span class=\"n\">ctr_1</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_00</span><span class=\"p\">[</span><span class=\"n\">ctr_1</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_01</span><span class=\"p\">[</span><span class=\"n\">ctr_1</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">0.25</span><span class=\"o\">*</span><span class=\"n\">_data_src_0m1</span><span class=\"p\">[</span><span class=\"n\">ctr_1</span><span class=\"p\">];</span>\n", " <span class=\"p\">}</span>\n", @@ -397,13 +408,13 @@ "text/plain": [ "FUNC_PREFIX void kernel(double * RESTRICT _data_dst, double * RESTRICT const _data_src)\n", "{\n", - " for (int ctr_0 = 1; ctr_0 < 29; ctr_0 += 1)\n", + " for (int64_t ctr_0 = 1; ctr_0 < 29; ctr_0 += 1)\n", " {\n", " double * RESTRICT _data_dst_00 = _data_dst + 30*ctr_0;\n", " double * RESTRICT _data_src_01 = _data_src + 30*ctr_0 + 30;\n", " double * RESTRICT _data_src_00 = _data_src + 30*ctr_0;\n", " double * RESTRICT _data_src_0m1 = _data_src + 30*ctr_0 - 30;\n", - " for (int ctr_1 = 1; ctr_1 < 29; ctr_1 += 1)\n", + " for (int64_t ctr_1 = 1; ctr_1 < 29; ctr_1 += 1)\n", " {\n", " _data_dst_00[ctr_1] = 0.25*_data_src_00[ctr_1 + 1] + 0.25*_data_src_00[ctr_1 - 1] + 0.25*_data_src_01[ctr_1] + 0.25*_data_src_0m1[ctr_1];\n", " }\n", @@ -456,7 +467,7 @@ "### 1.2. GPU simulations\n", "\n", "Let's now jump to a seemingly unrelated topic: running kernels on the GPU. \n", - "When creating the kernel, an additional parameter `target='gpu'` has to be passed. Also, the compiled kernel cannot be called with numpy arrays directly, but has to be called with `pycuda.gpuarray`s instead. That means, we have to transfer our numpy array to GPU first. From this step we obtain a gpuarray, then we can run the kernel, hopefully multiple times so that the data transfer was worth the time. Finally we transfer the finished result back to CPU:" + "When creating the kernel, an additional parameter `target=ps.Target.GPU` has to be passed. Also, the compiled kernel cannot be called with numpy arrays directly, but has to be called with `pycuda.gpuarray`s instead. That means, we have to transfer our numpy array to GPU first. From this step we obtain a gpuarray, then we can run the kernel, hopefully multiple times so that the data transfer was worth the time. Finally we transfer the finished result back to CPU:" ] }, { @@ -466,7 +477,8 @@ "outputs": [], "source": [ "if pycuda:\n", - " kernel_function_gpu = ps.create_kernel(update_rule, target='gpu').compile()\n", + " config = ps.CreateKernelConfig(target=ps.Target.GPU)\n", + " kernel_function_gpu = ps.create_kernel(update_rule, config=config).compile()\n", " # transfer to GPU\n", " src_arr_gpu = pycuda.gpuarray.to_gpu(src_arr)\n", " dst_arr_gpu = pycuda.gpuarray.to_gpu(dst_arr)\n", @@ -637,7 +649,7 @@ "metadata": {}, "outputs": [], "source": [ - "dh = ps.create_data_handling(domain_size=(30, 30), default_target='gpu')\n", + "dh = ps.create_data_handling(domain_size=(30, 30), default_target=ps.Target.GPU)\n", "\n", "# fields are now created using the data handling\n", "src_field = dh.add_array('src', values_per_cell=1)\n", @@ -646,7 +658,8 @@ "# kernel is created just like before\n", "update_rule = [ps.Assignment(lhs=dst_field[0, 0],\n", " rhs=(src_field[1, 0] + src_field[-1, 0] + src_field[0, 1] + src_field[0, -1]) / 4)]\n", - "kernel_function = ps.create_kernel(update_rule, target=dh.default_target).compile()\n", + "config = ps.CreateKernelConfig(target=dh.default_target)\n", + "kernel_function = ps.create_kernel(update_rule, config=config).compile()\n", "\n", "dh.fill('src', 0.0)" ] @@ -738,7 +751,7 @@ "outputs": [ { "data": { - "image/png": "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q+o/d/cHVzwbALA3uxmAjbRvYHZ3J/nK4sPzF2+9yqEAgJOzmwHYVEu9BrOqzquqa5PcmuTq7v7QascCAE7FbgZgEy0VmN19R3dfkuTCJE+oqu+66zFVdUVVHa2qo8ePH5+eEwA4gd0MwCY6rbvIdvdtSa5JcvkeP3dldx/p7iM7OztD4wEAp2I3A7BJlrmL7E5V3X/x/r2TPDnJJ1c9GACwN7sZgE21zF1kH5zkVVV1XnaD9PXd/dbVjgUAnILdDMBGWuYush9P8rhzMAsAsAS7GYBNdVqvwQQAAICTEZgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACMEJgAAACM2Dcwq+qhVfXeqrq+qq6rqheei8EAgL3ZzQBsqkNLHHN7khd190er6n5JjlXV1d39xyueDQDYm90MwEba9xnM7v7z7v7o4v0vJ7k+yQWrHgwA2JvdDMCmOq3XYFbV4SSPS/KhVQwDAJweuxmATbJ0YFbVfZO8McnPdveX9vj5K6rqaFUdPX78+OSMAMAe7GYANs1SgVlV52d3gb26u9+01zHdfWV3H+nuIzs7O5MzAgB3YTcDsImWuYtsJfmtJNd390tXPxIAcCp2MwCbaplnMC9N8vwkl1XVtYu3H1jxXADAydnNAGykfb9NSXe/P0mdg1kAgCXYzQBsqtO6iywAAACcjMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABghMAEAABg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\n", + "image/png": "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BmZ3d5KvLj48f/HWqxwKADgxuxmATbXUazCr6ryqujrJzUmu6u4PrHQqAOCk7GYANtFSgdndt3X3JUkuTPKoqvq+Ox5TVZdX1eGqOnz06NHhMQGAY9nNAGyi07qLbHffkuRdSS47zs9d0d2HuvvQ3t7e0HgAwMnYzQBskmXuIrtXVfdevH/3JI9P8skVzwUAnIDdDMCmWuYusvdP8vKqOi/7Qfqa7n7TascCAE7CbgZgIy1zF9mPJXnkOZgFAFiC3QzApjqt12ACAADAiQhMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARghMAAAARpwyMKvqgVX1rqr6RFVdU1XPPReDAQDHZzcDsKkOLHHMrUme190frqp7JTlSVVd19ydWPBsAcHx2MwAb6ZTPYHb3n3b3hxfvfyXJtUkuWPVgAMDx2c0AbKrTeg1mVR1M8sgkH1jJNADAabGbAdgkSwdmVd0zyeuS/EJ3f/k4P395VR2uqsNHjx6dnBEAOA67GYBNs1RgVtX52V9gr+ju1x/vmO6+orsPdfehvb29yRkBgDuwmwHYRMvcRbaS/E6Sa7v7hasfCQA4GbsZgE21zDOYj03y7CSXVtXVi7cfXfFcAMCJ2c0AbKRTfpuS7n5vkjoHswAAS7CbAdhUp3UXWQAAADgRgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkAAMAIgQkA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\n", "text/plain": [ "<Figure size 1152x432 with 2 Axes>" ] @@ -793,10 +806,15 @@ "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "(-1, -1) (32, 32)\n" + "ename": "ValueError", + "evalue": "Cannot create parallel data handling because walberla module is not available", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m<ipython-input-20-779cf1a58f81>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdh\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mps\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_data_handling\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdomain_size\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m30\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m30\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mparallel\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mfield\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_array\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'field'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mblock\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mdh\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0miterate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;31m# offset is in global coordinates, where first inner cell has coordiante (0,0)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;31m# and ghost layers have negative coordinates\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/git/pystencils/pystencils/datahandling/__init__.py\u001b[0m in \u001b[0;36mcreate_data_handling\u001b[0;34m(domain_size, periodicity, default_layout, default_target, parallel, default_ghost_layers, opencl_queue)\u001b[0m\n\u001b[1;32m 38\u001b[0m \u001b[0;32massert\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mopencl_queue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"OpenCL is only supported for SerialDataHandling\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 39\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mwlb\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 40\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Cannot create parallel data handling because walberla module is not available\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 41\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 42\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mperiodicity\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mFalse\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0mperiodicity\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mValueError\u001b[0m: Cannot create parallel data handling because walberla module is not available" ] } ], @@ -821,20 +839,9 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(-1, -1, -1) (22, 12, 22)\n", - "(19, -1, -1) (22, 12, 22)\n", - "(-1, -1, 19) (22, 12, 22)\n", - "(19, -1, 19) (22, 12, 22)\n" - ] - } - ], + "outputs": [], "source": [ "from waLBerla import createUniformBlockGrid\n", "from pystencils.datahandling import ParallelDataHandling\n", @@ -857,24 +864,9 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGoAAAAVCAYAAACuVXuDAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADhUlEQVRoBe2Z7W3bMBCGHaMDGO0G6gZJs0GygeNO0HiDFv1l/yvSDdpOUCQbJBsE9Qb2BnW8gfs+jE5lJUo2bIoS0BxwOvL4dXqPR1LUYLvdDnyezWaZn39J/4tPCjxCPhgOPJrP5x+VPfVUL8luEMhyXxSjnzBDIBWMJc4lPzlFzUPlOHIqOS1Xke4m1/2WfCu+kW5Vrhcrn9tyq/7OlN6E+k1tk9mQ23YwTmpP0Gwkv9OniyhlRkp/lmx0Eg1EAPPapbyH2v5S9pE+xF+Vpq97pTOv2tFJ9TcS34q/qbMf4tr+VSeJTTUvdRROsh0McTS+eXaUJJHAizeSGuHlCkl/LSUA3lmh0sxw8jv7tTb7SPoVX4mJ6J91bVSezKayDRo7Fk5g51Yp26Mm6tyFWHlQy6ucJQ/w4TJdSbEoK5V/FF+orZsVgfI2VZ3YFBOn3Cf4ZjTUg71pn33kfd4wBO6FlOtAgfVLeWrqyqbYOIHhhIi6FD80oSgHEcrBJQxvN7XNyyp72h5tDq7SlU0t4YRvLnHUO/GyDhUNnqmMfcGio1zVnBBaEq3uPs60ujFkcptaxAnfZDgKEEPLlgHGyaNx/7KKDfJNQ1lXRbFtagsnfOMcxewLRoMcxMkpuOR56DY52WY231UpKalNLePESjYiooKUhzJH7rolz7VTuTk5tLyZrrGPoAFHKFPalAAnF0ivhAezzwD14WFv4qaCDzefTpXhigP9SpIPWzY86pfJIqrxsFJuFCmfyqa2ccI3axzFbK+ALAfwohWApX9CL8l3ihFOs+sj0yHPxAvV3ZhSaaK0yJu+BZnEJr1LKzh5eDDZV0M9FuJzr2BXEg/DBclYDhtrSb7JHClNnYn4w7PG3Seie1IZVzsxyA4EFrlFnx3aZDYcjJN1kEs32U90pc5Sxt0Zl6i1pHIOFUSefbxyPcTdHndSA0kMI6o2Yg4POP+L9EyEgpS3T4Hai9Sick1CfdhyjC2MyxisDNwtFidUpZPZpLEdacwoOHn9gdfU/YuSs5Y4LMW/FsbQWGPxKNV4+4zTU5sy2bXEfpY+iEio/LZwJe08OKQQeX2iPtrEQe3vpWy+XHCSqxwqYiOpMViOUn9XNb5GT23CF/jELeUWUbwIp7hdH7fUO5auNbjb147tKGL7PtqEL4pVrvjDy0sLQLw47iGQmPffkPDnEvxOsrgo+AP8ixo954XzTQAAAABJRU5ErkJggg==\n", - "text/latex": [ - "$\\displaystyle \\left( 40, \\ 10, \\ 40\\right)$" - ], - "text/plain": [ - "(40, 10, 40)" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "dh.gather_array('field').shape" ] @@ -890,7 +882,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -917,22 +909,9 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 1152x432 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "dh.fill('src', 0.0)\n", "for block in dh.iterate(ghost_layers=False, inner_ghost_layers=False):\n", @@ -951,7 +930,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -964,22 +943,9 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "<Figure size 1152x432 with 1 Axes>" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plt.scalar_field( dh.gather_array('src') );" ] @@ -1001,9 +967,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.2" + "version": "3.9.2" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/doc/notebooks/06_tutorial_phasefield_dentritic_growth.ipynb b/doc/notebooks/06_tutorial_phasefield_dentritic_growth.ipynb index b998888c18197d56514214f0f01031e369d16617..0f8bfaf95cf0da3745f55389f1a892ca61c0fc50 100644 --- a/doc/notebooks/06_tutorial_phasefield_dentritic_growth.ipynb +++ b/doc/notebooks/06_tutorial_phasefield_dentritic_growth.ipynb @@ -7,6 +7,7 @@ "outputs": [], "source": [ "from pystencils.session import *\n", + "import pystencils as ps\n", "sp.init_printing()\n", "frac = sp.Rational" ] @@ -32,7 +33,7 @@ "outputs": [], "source": [ "dh = ps.create_data_handling(domain_size=(300, 300), periodicity=True, \n", - " default_target='cpu')\n", + " default_target=ps.Target.CPU)\n", "φ_field = dh.add_array('phi', latex_name='φ')\n", "φ_field_tmp = dh.add_array('phi_temp', latex_name='φ_temp')\n", "φ_delta_field = dh.add_array('phidelta', latex_name='φ_D')\n", @@ -299,7 +300,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "When creating the kernels we pass as target (which may be 'cpu' or 'gpu') the default target of the target handling. This enables to switch to a GPU simulation just by changing the parameter of the data handling.\n", + "When creating the kernels we pass as target (which may be 'Target.CPU' or 'Target.GPU') the default target of the target handling. This enables to switch to a GPU simulation just by changing the parameter of the data handling.\n", "\n", "The rest is similar to the previous tutorial." ] @@ -457,4 +458,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/doc/notebooks/demo_wave_equation.ipynb b/doc/notebooks/demo_wave_equation.ipynb index 2aa083d96b33e6b2c69bee0783e1c55b4ab616fd..e40131a1224a84158143799dbd17b73d1d9e4b10 100644 --- a/doc/notebooks/demo_wave_equation.ipynb +++ b/doc/notebooks/demo_wave_equation.ipynb @@ -8,6 +8,8 @@ }, "outputs": [], "source": [ + "import psutil\n", + "\n", "from pystencils.session import *\n", "\n", "import shutil" @@ -454,7 +456,7 @@ " print('No llvmlite installed')\n", "\n", "if llvmlite:\n", - " kernel = ps.create_kernel(update_rule, target='llvm').compile()\n", + " kernel = ps.create_kernel(update_rule, backend=ps.Backend.LLVM).compile()\n", " \n", " X,Y = np.meshgrid( np.linspace(0, 1, size[1]), np.linspace(0,1, size[0]))\n", " Z = np.sin(2*X*np.pi) * np.sin(2*Y*np.pi)\n", @@ -625,7 +627,7 @@ "\n", "res = None\n", "if pycuda:\n", - " gpu_ast = ps.create_kernel(update_rule, target='gpu')\n", + " gpu_ast = ps.create_kernel(update_rule, target=ps.Target.GPU)\n", " gpu_kernel = gpu_ast.compile()\n", " res = ps.show_code(gpu_ast)\n", "res" @@ -694,4 +696,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/doc/sphinx/kernel_compile_and_call.rst b/doc/sphinx/kernel_compile_and_call.rst index 42468177ed77e4173db1d345109dc415085bf755..fbe3e25114451f81eab688b2fd7e334899454ae3 100644 --- a/doc/sphinx/kernel_compile_and_call.rst +++ b/doc/sphinx/kernel_compile_and_call.rst @@ -8,6 +8,10 @@ Creating kernels .. autofunction:: pystencils.create_kernel +.. autofunction:: pystencils.CreateKernelConfig + +.. autofunction:: pystencils.create_domain_kernel + .. autofunction:: pystencils.create_indexed_kernel .. autofunction:: pystencils.create_staggered_kernel diff --git a/pystencils/__init__.py b/pystencils/__init__.py index f58f970ea3b216a8233f1386dddbae74c5e0dc04..3dc1abcd4d4956ce23bda209b540c2d73f0ea770 100644 --- a/pystencils/__init__.py +++ b/pystencils/__init__.py @@ -1,30 +1,33 @@ """Module to generate stencil kernels in C or CUDA using sympy expressions and call them as Python functions""" +from .enums import Backend, Target from . import fd from . import stencil as stencil from .assignment import Assignment, assignment_from_stencil from .data_types import TypedSymbol from .datahandling import create_data_handling -from .display_utils import show_code, get_code_obj, get_code_str, to_dot +from .display_utils import get_code_obj, get_code_str, show_code, to_dot from .field import Field, FieldType, fields from .kernel_decorator import kernel -from .kernelcreation import create_indexed_kernel, create_kernel, create_staggered_kernel +from .kernelcreation import ( + CreateKernelConfig, create_domain_kernel, create_indexed_kernel, create_kernel, create_staggered_kernel) from .simp import AssignmentCollection from .slicing import make_slice +from .spatial_coordinates import x_, x_staggered, x_staggered_vector, x_vector, y_, y_staggered, z_, z_staggered from .sympyextensions import SymbolCreator -from .spatial_coordinates import (x_, x_staggered, x_staggered_vector, x_vector, - y_, y_staggered, z_, z_staggered) try: import pystencils_autodiff + autodiff = pystencils_autodiff except ImportError: pass - __all__ = ['Field', 'FieldType', 'fields', 'TypedSymbol', 'make_slice', - 'create_kernel', 'create_indexed_kernel', 'create_staggered_kernel', + 'create_kernel', 'create_domain_kernel', 'create_indexed_kernel', 'create_staggered_kernel', + 'CreateKernelConfig', + 'Target', 'Backend', 'show_code', 'to_dot', 'get_code_obj', 'get_code_str', 'AssignmentCollection', 'Assignment', @@ -39,5 +42,6 @@ __all__ = ['Field', 'FieldType', 'fields', 'stencil'] from ._version import get_versions + __version__ = get_versions()['version'] del get_versions diff --git a/pystencils/astnodes.py b/pystencils/astnodes.py index 8690546216b8da10c3acabc3fad485bba6ada967..92ea54960ce735d678abb18312d708480338c90f 100644 --- a/pystencils/astnodes.py +++ b/pystencils/astnodes.py @@ -7,6 +7,7 @@ import sympy as sp import pystencils from pystencils.data_types import TypedImaginaryUnit, TypedSymbol, cast_func, create_type +from pystencils.enums import Target, Backend from pystencils.field import Field from pystencils.kernelparameters import FieldPointerSymbol, FieldShapeSymbol, FieldStrideSymbol from pystencils.sympyextensions import fast_subs @@ -136,7 +137,6 @@ class Conditional(Node): class KernelFunction(Node): - class Parameter: """Function parameter. @@ -176,7 +176,9 @@ class KernelFunction(Node): def field_name(self): return self.fields[0].name - def __init__(self, body, target, backend, compile_function, ghost_layers, function_name="kernel", assignments=None): + def __init__(self, body, target: Target, backend: Backend, compile_function, ghost_layers, + function_name: str = "kernel", + assignments=None): super(KernelFunction, self).__init__() self._body = body body.parent = self @@ -194,12 +196,12 @@ class KernelFunction(Node): @property def target(self): - """Currently either 'cpu' or 'gpu' """ + """See pystencils.Target""" return self._target @property def backend(self): - """Backend for generating the code e.g. 'llvm', 'c', 'cuda' """ + """Backend for generating the code: `Backend`""" return self._backend @property diff --git a/pystencils/backends/cbackend.py b/pystencils/backends/cbackend.py index 1b45294a62d7ff006e5d808a9a180548c72bfe9f..0e05094247ac82bcfc18e0356ea0ab24fc54743f 100644 --- a/pystencils/backends/cbackend.py +++ b/pystencils/backends/cbackend.py @@ -14,6 +14,7 @@ from pystencils.cpu.vectorization import vec_all, vec_any, CachelineSize from pystencils.data_types import ( PointerType, VectorType, address_of, cast_func, create_type, get_type_of_expression, reinterpret_cast_func, vector_memory_access, BasicType, TypedSymbol) +from pystencils.enums import Backend from pystencils.fast_approximation import fast_division, fast_inv_sqrt, fast_sqrt from pystencils.integer_functions import ( bit_shift_left, bit_shift_right, bitwise_and, bitwise_or, bitwise_xor, @@ -34,7 +35,7 @@ KERNCRAFT_NO_TERNARY_MODE = False def generate_c(ast_node: Node, signature_only: bool = False, - dialect='c', + dialect: Backend = Backend.C, custom_backend=None, with_globals=True) -> str: """Prints an abstract syntax tree node as C or CUDA code. @@ -46,7 +47,7 @@ def generate_c(ast_node: Node, Args: ast_node: ast representation of kernel signature_only: generate signature without function body - dialect: 'c', 'cuda' or opencl + dialect: `Backend`: 'C', 'CUDA' or 'OPENCL' custom_backend: use own custom printer for code generation with_globals: enable usage of global variables Returns: @@ -60,21 +61,21 @@ def generate_c(ast_node: Node, ast_node.global_variables = d.symbols_defined if custom_backend: printer = custom_backend - elif dialect == 'c': + elif dialect == Backend.C: try: instruction_set = ast_node.instruction_set except Exception: instruction_set = None printer = CBackend(signature_only=signature_only, vector_instruction_set=instruction_set) - elif dialect == 'cuda': + elif dialect == Backend.CUDA: from pystencils.backends.cuda_backend import CudaBackend printer = CudaBackend(signature_only=signature_only) - elif dialect == 'opencl': + elif dialect == Backend.OPENCL: from pystencils.backends.opencl_backend import OpenClBackend printer = OpenClBackend(signature_only=signature_only) else: - raise ValueError("Unknown dialect: " + str(dialect)) + raise ValueError(f'Unknown {dialect=}') code = printer(ast_node) if not signature_only and isinstance(ast_node, KernelFunction): if with_globals and global_declarations: @@ -189,7 +190,7 @@ class CFunction(TypedSymbol): # noinspection PyPep8Naming class CBackend: - def __init__(self, sympy_printer=None, signature_only=False, vector_instruction_set=None, dialect='c'): + def __init__(self, sympy_printer=None, signature_only=False, vector_instruction_set=None, dialect=Backend.C): if sympy_printer is None: if vector_instruction_set is not None: self.sympy_printer = VectorizedCustomSympyPrinter(vector_instruction_set) @@ -228,7 +229,7 @@ class CBackend: function_arguments = [f"{self._print(s.symbol.dtype)} {s.symbol.name}" for s in node.get_parameters() if not type(s.symbol) is CFunction] launch_bounds = "" - if self._dialect == 'cuda': + if self._dialect == Backend.CUDA: max_threads = node.indexing.max_threads_per_block() if max_threads: launch_bounds = f"__launch_bounds__({max_threads}) " diff --git a/pystencils/backends/cuda_backend.py b/pystencils/backends/cuda_backend.py index b699c9ce40be6f08c39d113768028abf15056b0a..20bc8bf7b372391daac21737462ff2fa6b077c70 100644 --- a/pystencils/backends/cuda_backend.py +++ b/pystencils/backends/cuda_backend.py @@ -2,6 +2,7 @@ from os.path import dirname, join from pystencils.astnodes import Node from pystencils.backends.cbackend import CBackend, CustomSympyPrinter, generate_c +from pystencils.enums import Backend from pystencils.fast_approximation import fast_division, fast_inv_sqrt, fast_sqrt from pystencils.interpolation_astnodes import DiffInterpolatorAccess, InterpolationMode @@ -22,7 +23,7 @@ def generate_cuda(ast_node: Node, signature_only: bool = False, custom_backend=N Returns: CUDA code for the ast node and its descendants """ - return generate_c(ast_node, signature_only, dialect='cuda', + return generate_c(ast_node, signature_only, dialect=Backend.CUDA, custom_backend=custom_backend, with_globals=with_globals) @@ -33,7 +34,7 @@ class CudaBackend(CBackend): if not sympy_printer: sympy_printer = CudaSympyPrinter() - super().__init__(sympy_printer, signature_only, dialect='cuda') + super().__init__(sympy_printer, signature_only, dialect=Backend.CUDA) def _print_SharedMemoryAllocation(self, node): dtype = node.symbol.dtype diff --git a/pystencils/backends/opencl_backend.py b/pystencils/backends/opencl_backend.py index be9d6adb35654301af0c18a4491c2fc3fe93dce6..c2d71e4d202549e21cc877d0a159792422ee66bd 100644 --- a/pystencils/backends/opencl_backend.py +++ b/pystencils/backends/opencl_backend.py @@ -4,6 +4,7 @@ import pystencils.data_types from pystencils.astnodes import Node from pystencils.backends.cbackend import CustomSympyPrinter, generate_c from pystencils.backends.cuda_backend import CudaBackend, CudaSympyPrinter +from pystencils.enums import Backend from pystencils.fast_approximation import fast_division, fast_inv_sqrt, fast_sqrt with open(join(dirname(__file__), 'opencl1.1_known_functions.txt')) as f: @@ -12,7 +13,7 @@ with open(join(dirname(__file__), 'opencl1.1_known_functions.txt')) as f: def generate_opencl(ast_node: Node, signature_only: bool = False, custom_backend=None, with_globals=True) -> str: - """Prints an abstract syntax tree node (made for target 'gpu') as OpenCL code. + """Prints an abstract syntax tree node (made for `Target` 'GPU') as OpenCL code. # TODO Backend instead of Target? Args: ast_node: ast representation of kernel @@ -23,7 +24,7 @@ def generate_opencl(ast_node: Node, signature_only: bool = False, custom_backend Returns: OpenCL code for the ast node and its descendants """ - return generate_c(ast_node, signature_only, dialect='opencl', + return generate_c(ast_node, signature_only, dialect=Backend.OPENCL, custom_backend=custom_backend, with_globals=with_globals) @@ -36,7 +37,7 @@ class OpenClBackend(CudaBackend): sympy_printer = OpenClSympyPrinter() super().__init__(sympy_printer, signature_only) - self._dialect = 'opencl' + self._dialect = Backend.OPENCL def _print_Type(self, node): code = super()._print_Type(node) diff --git a/pystencils/boundaries/boundaryhandling.py b/pystencils/boundaries/boundaryhandling.py index 077b1cd500037ce55508a43471a9a6d077d6a94f..5705d3d53ad4941137e59819383c8d606e49afb2 100644 --- a/pystencils/boundaries/boundaryhandling.py +++ b/pystencils/boundaries/boundaryhandling.py @@ -1,7 +1,7 @@ import numpy as np import sympy as sp -from pystencils import create_indexed_kernel +from pystencils import create_kernel, CreateKernelConfig, Target from pystencils.assignment import Assignment from pystencils.backends.cbackend import CustomCodeNode from pystencils.boundaries.createindexlist import ( @@ -84,7 +84,7 @@ class FlagInterface: class BoundaryHandling: def __init__(self, data_handling, field_name, stencil, name="boundary_handling", flag_interface=None, - target='cpu', openmp=True): + target: Target = Target.CPU, openmp=True): assert data_handling.has_data(field_name) assert data_handling.dim == len(stencil[0]), "Dimension of stencil and data handling do not match" self._data_handling = data_handling @@ -442,9 +442,10 @@ class BoundaryOffsetInfo(CustomCodeNode): INV_DIR_SYMBOL = TypedSymbol("invdir", np.int64) -def create_boundary_kernel(field, index_field, stencil, boundary_functor, target='cpu', **kernel_creation_args): +def create_boundary_kernel(field, index_field, stencil, boundary_functor, target=Target.CPU, **kernel_creation_args): elements = [BoundaryOffsetInfo(stencil)] dir_symbol = TypedSymbol("dir", np.int64) elements += [Assignment(dir_symbol, index_field[0]('dir'))] elements += boundary_functor(field, direction_symbol=dir_symbol, index_field=index_field) - return create_indexed_kernel(elements, [index_field], target=target, **kernel_creation_args) + config = CreateKernelConfig(index_fields=[index_field], target=target, **kernel_creation_args) + return create_kernel(elements, config=config) diff --git a/pystencils/cpu/kernelcreation.py b/pystencils/cpu/kernelcreation.py index 8b5d0e4d270ff1a8e4dee59578037ad4ff505993..0ce1b585db41b2cf90b0d5bf849222d03fdf3921 100644 --- a/pystencils/cpu/kernelcreation.py +++ b/pystencils/cpu/kernelcreation.py @@ -5,6 +5,7 @@ import numpy as np import pystencils.astnodes as ast from pystencils.assignment import Assignment +from pystencils.enums import Target, Backend from pystencils.astnodes import Block, KernelFunction, LoopOverCoordinate, SympyAssignment from pystencils.cpu.cpujit import make_python_function from pystencils.data_types import StructType, TypedSymbol, create_type @@ -70,7 +71,7 @@ def create_kernel(assignments: AssignmentOrAstNodeList, function_name: str = "ke loop_order = get_optimal_loop_ordering(fields_without_buffers) loop_node, ghost_layer_info = make_loop_over_domain(body, iteration_slice=iteration_slice, ghost_layers=ghost_layers, loop_order=loop_order) - ast_node = KernelFunction(loop_node, 'cpu', 'c', compile_function=make_python_function, + ast_node = KernelFunction(loop_node, Target.CPU, Backend.C, compile_function=make_python_function, ghost_layers=ghost_layer_info, function_name=function_name, assignments=assignments) implement_interpolations(body) @@ -151,7 +152,7 @@ def create_indexed_kernel(assignments: AssignmentOrAstNodeList, index_fields, fu loop_body.append(assignment) function_body = Block([loop_node]) - ast_node = KernelFunction(function_body, "cpu", "c", make_python_function, + ast_node = KernelFunction(function_body, Target.CPU, Backend.C, make_python_function, ghost_layers=None, function_name=function_name, assignments=assignments) fixed_coordinate_mapping = {f.name: coordinate_typed_symbols for f in non_index_fields} diff --git a/pystencils/datahandling/__init__.py b/pystencils/datahandling/__init__.py index a4fa55bdc7a52e1b9c2015e2210fcbb48aaeb2e1..139ac4e7d4127e37818399374f5bb0c76d8f1980 100644 --- a/pystencils/datahandling/__init__.py +++ b/pystencils/datahandling/__init__.py @@ -1,6 +1,9 @@ +import warnings + from typing import Tuple, Union from .datahandling_interface import DataHandling +from ..enums import Target from .serial_datahandling import SerialDataHandling try: @@ -18,7 +21,7 @@ except ImportError: def create_data_handling(domain_size: Tuple[int, ...], periodicity: Union[bool, Tuple[bool, ...]] = False, default_layout: str = 'SoA', - default_target: str = 'cpu', + default_target: Target = Target.CPU, parallel: bool = False, default_ghost_layers: int = 1, opencl_queue=None) -> DataHandling: @@ -29,10 +32,16 @@ def create_data_handling(domain_size: Tuple[int, ...], periodicity: either True, False for full or no periodicity or a tuple of booleans indicating periodicity for each coordinate default_layout: default array layout, that is used if not explicitly specified in 'add_array' - default_target: either 'cpu' or 'gpu' + default_target: `Target` parallel: if True a parallel domain is created using walberla - each MPI process gets a part of the domain default_ghost_layers: default number of ghost layers if not overwritten in 'add_array' """ + if isinstance(default_target, str): + new_target = Target[default_target.upper()] + warnings.warn(f'Target "{default_target}" as str is deprecated. Use {new_target} instead', + category=DeprecationWarning) + default_target = new_target + if parallel: assert not opencl_queue, "OpenCL is only supported for SerialDataHandling" if wlb is None: diff --git a/pystencils/datahandling/datahandling_interface.py b/pystencils/datahandling/datahandling_interface.py index 0eb101815ec39788cb2b1b9e720f2628bf087edf..d01a64625181a874997d896ebe1c43eccf6ec6bd 100644 --- a/pystencils/datahandling/datahandling_interface.py +++ b/pystencils/datahandling/datahandling_interface.py @@ -3,6 +3,7 @@ from typing import Callable, Dict, Iterable, Optional, Sequence, Tuple, Union import numpy as np +from pystencils.enums import Target, Backend from pystencils.field import Field, FieldType @@ -16,8 +17,8 @@ class DataHandling(ABC): 'gather' function that has collects (parts of the) distributed data on a single process. """ - _GPU_LIKE_TARGETS = ['gpu', 'opencl'] - _GPU_LIKE_BACKENDS = ['gpucuda', 'opencl'] + _GPU_LIKE_TARGETS = [Target.GPU, Target.OPENCL] + _GPU_LIKE_BACKENDS = [Backend.CUDA, Backend.OPENCL] # ---------------------------- Adding and accessing data ----------------------------------------------------------- @@ -56,7 +57,7 @@ class DataHandling(ABC): layout: memory layout of array, either structure of arrays 'SoA' or array of structures 'AoS'. this is only important if values_per_cell > 1 cpu: allocate field on the CPU - gpu: allocate field on the GPU, if None, a GPU field is allocated if default_target is 'gpu' + gpu: allocate field on the GPU, if None, a GPU field is allocated if default_target is 'GPU' alignment: either False for no alignment, or the number of bytes to align to Returns: pystencils field, that can be used to formulate symbolic kernels @@ -91,7 +92,7 @@ class DataHandling(ABC): layout: memory layout of array, either structure of arrays 'SoA' or array of structures 'AoS'. this is only important if values_per_cell > 1 cpu: allocate field on the CPU - gpu: allocate field on the GPU, if None, a GPU field is allocated if default_target is 'gpu' + gpu: allocate field on the GPU, if None, a GPU field is allocated if default_target is 'GPU' alignment: either False for no alignment, or the number of bytes to align to Returns: Fields representing the just created arrays @@ -280,7 +281,7 @@ class DataHandling(ABC): names: what data to synchronize: name of array or sequence of names stencil: stencil as string defining which neighbors are synchronized e.g. 'D2Q9', 'D3Q19' if None, a full synchronization (i.e. D2Q9 or D3Q27) is done - target: either 'cpu' or 'gpu + target: `Target` either 'CPU' or 'GPU' kwargs: implementation specific, optional optimization parameters for communication Returns: diff --git a/pystencils/datahandling/parallel_datahandling.py b/pystencils/datahandling/parallel_datahandling.py index 9c1462407803c24b0b05f4157c4d739fb5353014..4e94d780d9f7f33d3aeb5ce2b53dcc52f910221a 100644 --- a/pystencils/datahandling/parallel_datahandling.py +++ b/pystencils/datahandling/parallel_datahandling.py @@ -7,16 +7,18 @@ import waLBerla as wlb from pystencils.datahandling.blockiteration import block_iteration, sliced_block_iteration from pystencils.datahandling.datahandling_interface import DataHandling +from pystencils.enums import Backend from pystencils.field import Field, FieldType from pystencils.kernelparameters import FieldPointerSymbol from pystencils.utils import DotDict +from pystencils import Target class ParallelDataHandling(DataHandling): GPU_DATA_PREFIX = "gpu_" VTK_COUNTER = 0 - def __init__(self, blocks, default_ghost_layers=1, default_layout='SoA', dim=3, default_target='cpu'): + def __init__(self, blocks, default_ghost_layers=1, default_layout='SoA', dim=3, default_target=Target.CPU): """ Creates data handling based on walberla block storage @@ -27,8 +29,9 @@ class ParallelDataHandling(DataHandling): dim: dimension of scenario, walberla always uses three dimensions, so if dim=2 the extend of the z coordinate of blocks has to be 1 - default_target: either 'cpu' or 'gpu' . If set to 'gpu' for each array also a GPU version is allocated - if not overwritten in add_array, and synchronization functions are for the GPU by default + default_target: `Target`, either 'CPU' or 'GPU' . If set to 'GPU' for each array also a GPU version is + allocated if not overwritten in add_array, and synchronization functions are for the GPU by + default """ super(ParallelDataHandling, self).__init__() assert dim in (2, 3) @@ -94,7 +97,7 @@ class ParallelDataHandling(DataHandling): if ghost_layers is None: ghost_layers = self.default_ghost_layers if gpu is None: - gpu = self.default_target == 'gpu' + gpu = self.default_target == Target.GPU if layout is None: layout = self.default_layout if len(self.blocks) == 0: @@ -230,7 +233,7 @@ class ParallelDataHandling(DataHandling): kernel_function(**arg_dict) def get_kernel_kwargs(self, kernel_function, **kwargs): - if kernel_function.ast.backend == 'gpucuda': + if kernel_function.ast.backend == Backend.CUDA: name_map = self._field_name_to_gpu_data_name to_array = wlb.cuda.toGpuArray else: @@ -283,10 +286,10 @@ class ParallelDataHandling(DataHandling): self.to_gpu(name) def synchronization_function_cpu(self, names, stencil=None, buffered=True, stencil_restricted=False, **_): - return self.synchronization_function(names, stencil, 'cpu', buffered, stencil_restricted) + return self.synchronization_function(names, stencil, Target.CPU, buffered, stencil_restricted) def synchronization_function_gpu(self, names, stencil=None, buffered=True, stencil_restricted=False, **_): - return self.synchronization_function(names, stencil, 'gpu', buffered, stencil_restricted) + return self.synchronization_function(names, stencil, Target.GPU, buffered, stencil_restricted) def synchronization_function(self, names, stencil=None, target=None, buffered=True, stencil_restricted=False): if target is None: @@ -299,12 +302,12 @@ class ParallelDataHandling(DataHandling): names = [names] create_scheme = wlb.createUniformBufferedScheme if buffered else wlb.createUniformDirectScheme - if target == 'cpu': + if target == Target.CPU: create_packing = wlb.field.createPackInfo if buffered else wlb.field.createMPIDatatypeInfo if buffered and stencil_restricted: create_packing = wlb.field.createStencilRestrictedPackInfo else: - assert target == 'gpu' + assert target == Target.GPU create_packing = wlb.cuda.createPackInfo if buffered else wlb.cuda.createMPIDatatypeInfo names = [self.GPU_DATA_PREFIX + name for name in names] diff --git a/pystencils/datahandling/serial_datahandling.py b/pystencils/datahandling/serial_datahandling.py index 9e18acf4a240932bcdb0aad80a899cbe6d411a3f..aed4caa7b991101efebf10e94b1591d07ebc1bec 100644 --- a/pystencils/datahandling/serial_datahandling.py +++ b/pystencils/datahandling/serial_datahandling.py @@ -8,6 +8,7 @@ from pystencils.datahandling.blockiteration import SerialBlock from pystencils.datahandling.datahandling_interface import DataHandling from pystencils.datahandling.pycuda import PyCudaArrayHandler, PyCudaNotAvailableHandler from pystencils.datahandling.pyopencl import PyOpenClArrayHandler +from pystencils.enums import Target from pystencils.field import ( Field, FieldType, create_numpy_array_with_layout, layout_string_to_tuple, spatial_layout_string_to_tuple) @@ -22,7 +23,7 @@ class SerialDataHandling(DataHandling): default_ghost_layers: int = 1, default_layout: str = 'SoA', periodicity: Union[bool, Sequence[bool]] = False, - default_target: str = 'cpu', + default_target: Target = Target.CPU, opencl_queue=None, opencl_ctx=None, array_handler=None) -> None: @@ -33,8 +34,9 @@ class SerialDataHandling(DataHandling): domain_size: size of the spatial domain as tuple default_ghost_layers: default number of ghost layers used, if not overridden in add_array() method default_layout: default layout used, if not overridden in add_array() method - default_target: either 'cpu' or 'gpu' . If set to 'gpu' for each array also a GPU version is allocated - if not overwritten in add_array, and synchronization functions are for the GPU by default + default_target: `Target` either 'CPU' or 'GPU'. If set to 'GPU' for each array also a GPU version is + allocated if not overwritten in add_array, and synchronization functions are for the GPU by + default """ super(SerialDataHandling, self).__init__() self._domainSize = tuple(domain_size) @@ -55,7 +57,7 @@ class SerialDataHandling(DataHandling): except Exception: self.array_handler = PyCudaNotAvailableHandler() - if default_target == 'opencl' or opencl_queue: + if default_target == Target.OPENCL or opencl_queue: self.array_handler = PyOpenClArrayHandler(opencl_queue) else: self.array_handler = array_handler @@ -107,7 +109,7 @@ class SerialDataHandling(DataHandling): } if not hasattr(values_per_cell, '__len__'): - values_per_cell = (values_per_cell, ) + values_per_cell = (values_per_cell,) if len(values_per_cell) == 1 and values_per_cell[0] == 1: values_per_cell = () @@ -266,17 +268,17 @@ class SerialDataHandling(DataHandling): return name in self.gpu_arrays def synchronization_function_cpu(self, names, stencil_name=None, **_): - return self.synchronization_function(names, stencil_name, target='cpu') + return self.synchronization_function(names, stencil_name, target=Target.CPU) def synchronization_function_gpu(self, names, stencil_name=None, **_): - return self.synchronization_function(names, stencil_name, target='gpu') + return self.synchronization_function(names, stencil_name, target=Target.GPU) def synchronization_function(self, names, stencil=None, target=None, functor=None, **_): if target is None: target = self.default_target - if target == 'opencl': - target = 'gpu' - assert target in ('cpu', 'gpu') + if target == Target.OPENCL: # TODO potential misuse between Target and Backend + target = Target.GPU + assert target in (Target.CPU, Target.GPU) if not hasattr(names, '__len__') or type(names) is str: names = [names] @@ -305,12 +307,12 @@ class SerialDataHandling(DataHandling): gls = self._field_information[name]['ghost_layers'] values_per_cell = self._field_information[name]['values_per_cell'] if values_per_cell == (): - values_per_cell = (1, ) + values_per_cell = (1,) if len(values_per_cell) == 1: values_per_cell = values_per_cell[0] if len(filtered_stencil) > 0: - if target == 'cpu': + if target == Target.CPU: if functor is None: from pystencils.slicing import get_periodic_boundary_functor functor = get_periodic_boundary_functor @@ -318,7 +320,8 @@ class SerialDataHandling(DataHandling): else: if functor is None: from pystencils.gpucuda.periodicity import get_periodic_boundary_functor as functor - target = 'gpu' if not isinstance(self.array_handler, PyOpenClArrayHandler) else 'opencl' + target = Target.GPU if not isinstance(self.array_handler, + PyOpenClArrayHandler) else Target.OPENCL result.append(functor(filtered_stencil, self._domainSize, index_dimensions=self.fields[name].index_dimensions, index_dim_shape=values_per_cell, @@ -328,7 +331,7 @@ class SerialDataHandling(DataHandling): opencl_queue=self._opencl_queue, opencl_ctx=self._opencl_ctx)) - if target == 'cpu': + if target == Target.CPU: def result_functor(): for arr_name, func in zip(names, result): func(pdfs=self.cpu_arrays[arr_name]) @@ -379,6 +382,7 @@ class SerialDataHandling(DataHandling): raise NotImplementedError("VTK export for fields with more than one index " "coordinate not implemented") image_to_vtk(full_file_name, cell_data=cell_data) + return writer def create_vtk_writer_for_flag_array(self, file_name, data_name, masks_to_name, ghost_layers=False): diff --git a/pystencils/display_utils.py b/pystencils/display_utils.py index 32531cdc5e2bba37b46e5708859ed60e8150dea5..22492dd3af901b30b2c559602f5ca4eaea451f7b 100644 --- a/pystencils/display_utils.py +++ b/pystencils/display_utils.py @@ -3,6 +3,7 @@ from typing import Any, Dict, Optional, Union import sympy as sp from pystencils.astnodes import KernelFunction +from pystencils.enums import Backend from pystencils.kernel_wrapper import KernelWrapper @@ -45,12 +46,9 @@ def get_code_obj(ast: Union[KernelFunction, KernelWrapper], custom_backend=None) if isinstance(ast, KernelWrapper): ast = ast.ast - if ast.backend == 'gpucuda': - dialect = 'cuda' - elif ast.backend == 'opencl': - dialect = 'opencl' - else: - dialect = 'c' + if ast.backend not in {Backend.C, Backend.CUDA, Backend.OPENCL}: + raise NotImplementedError(f'get_code_obj is not implemented for backend {ast.backend}') + dialect = ast.backend class CodeDisplay: def __init__(self, ast_input): diff --git a/pystencils/enums.py b/pystencils/enums.py new file mode 100644 index 0000000000000000000000000000000000000000..afe20bb26fb9ec8d02258ba3f9049cc61ae66379 --- /dev/null +++ b/pystencils/enums.py @@ -0,0 +1,14 @@ +from enum import Enum, auto + + +class Target(Enum): + CPU = auto() + GPU = auto() + OPENCL = auto() + + +class Backend(Enum): + C = auto() + LLVM = auto() + CUDA = auto() + OPENCL = auto() diff --git a/pystencils/gpucuda/kernelcreation.py b/pystencils/gpucuda/kernelcreation.py index 08226e260452680b5afcc4b6c493634b778b85a7..d26317a8cef1f357b59db5ca515bc0dc23c3a817 100644 --- a/pystencils/gpucuda/kernelcreation.py +++ b/pystencils/gpucuda/kernelcreation.py @@ -3,6 +3,7 @@ import numpy as np from pystencils.astnodes import Block, KernelFunction, LoopOverCoordinate, SympyAssignment from pystencils.data_types import StructType, TypedSymbol from pystencils.field import Field, FieldType +from pystencils.enums import Target, Backend from pystencils.gpucuda.cudajit import make_python_function from pystencils.gpucuda.indexing import BlockIndexing from pystencils.transformations import ( @@ -65,8 +66,8 @@ def create_cuda_kernel(assignments, unify_shape_symbols(block, common_shape=common_shape, fields=fields_without_buffers) ast = KernelFunction(block, - 'gpu', - 'gpucuda', + Target.GPU, + Backend.CUDA, make_python_function, ghost_layers, function_name, @@ -145,7 +146,7 @@ def created_indexed_cuda_kernel(assignments, function_body = Block(coordinate_symbol_assignments + assignments) function_body = indexing.guard(function_body, get_common_shape(index_fields)) - ast = KernelFunction(function_body, 'gpu', 'gpucuda', make_python_function, + ast = KernelFunction(function_body, Target.GPU, Backend.CUDA, make_python_function, None, function_name, assignments=assignments) ast.global_variables.update(indexing.index_variables) diff --git a/pystencils/gpucuda/periodicity.py b/pystencils/gpucuda/periodicity.py index a947d94a1ac24c922a8e9d19211b69b6cbd83004..da62af0f664ff9abc9e84edb24e2e20be02abcb9 100644 --- a/pystencils/gpucuda/periodicity.py +++ b/pystencils/gpucuda/periodicity.py @@ -5,6 +5,7 @@ import pystencils.gpucuda import pystencils.opencl from pystencils import Assignment, Field from pystencils.gpucuda.kernelcreation import create_cuda_kernel +from pystencils.enums import Target from pystencils.slicing import get_periodic_boundary_src_dst_slices, normalize_slice @@ -31,18 +32,18 @@ def create_copy_kernel(domain_size, from_slice, to_slice, index_dimensions=0, in def get_periodic_boundary_functor(stencil, domain_size, index_dimensions=0, index_dim_shape=1, ghost_layers=1, - thickness=None, dtype=float, target='gpu', opencl_queue=None, opencl_ctx=None): - assert target in ['gpu', 'opencl'] + thickness=None, dtype=float, target=Target.GPU, opencl_queue=None, opencl_ctx=None): + assert target in {Target.GPU, Target.OPENCL} src_dst_slice_tuples = get_periodic_boundary_src_dst_slices(stencil, ghost_layers, thickness) kernels = [] for src_slice, dst_slice in src_dst_slice_tuples: ast = create_copy_kernel(domain_size, src_slice, dst_slice, index_dimensions, index_dim_shape, dtype) - if target == 'gpu': + if target == pystencils.Target.GPU: kernels.append(pystencils.gpucuda.make_python_function(ast)) else: - ast._target = 'opencl' - ast._backend = 'opencl' + ast._target = pystencils.Target.OPENCL + ast._backend = pystencils.Backend.OPENCL kernels.append(pystencils.opencl.make_python_function(ast, opencl_queue, opencl_ctx)) def functor(pdfs, **_): diff --git a/pystencils/kerncraft_coupling/generate_benchmark.py b/pystencils/kerncraft_coupling/generate_benchmark.py index 6e69ef6bc42e775fc3dda60154061fc465fbc83f..955098d2cb8d53bf7f66e2f29f5a615bd619fe83 100644 --- a/pystencils/kerncraft_coupling/generate_benchmark.py +++ b/pystencils/kerncraft_coupling/generate_benchmark.py @@ -9,6 +9,7 @@ from pystencils.astnodes import PragmaBlock from pystencils.backends.cbackend import generate_c, get_headers from pystencils.cpu.cpujit import get_compiler_config, run_compile_step from pystencils.data_types import get_base_type +from pystencils.enums import Backend from pystencils.include import get_pystencils_include_path from pystencils.integer_functions import modulo_ceil from pystencils.sympyextensions import prod @@ -77,7 +78,7 @@ def generate_benchmark(ast, likwid=False, openmp=False, timing=False): jinja_context = { 'likwid': likwid, 'openmp': openmp, - 'kernel_code': generate_c(ast, dialect='c'), + 'kernel_code': generate_c(ast, dialect=Backend.C), 'kernelName': ast.function_name, 'fields': fields, 'constants': constants, diff --git a/pystencils/kerncraft_coupling/kerncraft_interface.py b/pystencils/kerncraft_coupling/kerncraft_interface.py index dd0b0d5c660b8cfecfef623770a8d88505041148..61867e518e10c5916f94e834c7c05e2ed145a570 100644 --- a/pystencils/kerncraft_coupling/kerncraft_interface.py +++ b/pystencils/kerncraft_coupling/kerncraft_interface.py @@ -15,6 +15,7 @@ from kerncraft.machinemodel import MachineModel from pystencils.astnodes import \ KernelFunction, LoopOverCoordinate, ResolvedFieldAccess, SympyAssignment from pystencils.backends.cbackend import generate_c, get_headers +from pystencils.enums import Backend from pystencils.field import get_layout_from_strides from pystencils.sympyextensions import count_operations_in_ast from pystencils.transformations import filtered_tree_iteration @@ -155,7 +156,7 @@ class PyStencilsKerncraftKernel(KernelCode): # use cache pass else: # lock_mode == fcntl.LOCK_EX: - function_signature = generate_c(self.kernel_ast, dialect='c', signature_only=True) + function_signature = generate_c(self.kernel_ast, dialect=Backend.C, signature_only=True) jinja_context = { 'function_signature': function_signature, @@ -195,7 +196,7 @@ class PyStencilsKerncraftKernel(KernelCode): if openmp: add_openmp(self.kernel_ast) - kernel_code = generate_c(self.kernel_ast, dialect='c') + kernel_code = generate_c(self.kernel_ast, dialect=Backend.C) jinja_context = { 'includes': includes, diff --git a/pystencils/kernel_decorator.py b/pystencils/kernel_decorator.py index 1ea8dcfbc4c671d8d0ba5634f2c55a93a39d9f23..92974a40f3dc9473eb3c586f11167c30cecdd968 100644 --- a/pystencils/kernel_decorator.py +++ b/pystencils/kernel_decorator.py @@ -1,6 +1,7 @@ import ast import inspect import textwrap +from typing import Callable, Union, List, Dict import sympy as sp @@ -10,7 +11,7 @@ from pystencils.sympyextensions import SymbolCreator __all__ = ['kernel'] -def kernel(func, **kwargs): +def kernel(func: Callable[..., None], return_config: bool = False, **kwargs) -> Union[List[Assignment], Dict]: """Decorator to simplify generation of pystencils Assignments. Changes the meaning of the '@=' operator. Each line containing this operator gives a symbolic assignment @@ -19,6 +20,9 @@ def kernel(func, **kwargs): The decorated function may not receive any arguments, with exception of an argument called 's' that specifies a SymbolCreator() + func: the decorated function + return_config: Specify whether to return the list with assignments, or a dictionary containing additional settings + like func_name Examples: >>> import pystencils as ps @@ -51,7 +55,10 @@ def kernel(func, **kwargs): if 's' in args and 's' not in kwargs: kwargs['s'] = SymbolCreator() func(**kwargs) - return assignments + if return_config: + return {'assignments': assignments, 'function_name': func.__name__} + else: + return assignments # noinspection PyMethodMayBeStatic diff --git a/pystencils/kernelcreation.py b/pystencils/kernelcreation.py index 423317939c176032738142f7e76162f7f539ea99..aa1fde55b1661c49267bd2e62fa1c067fb8759c4 100644 --- a/pystencils/kernelcreation.py +++ b/pystencils/kernelcreation.py @@ -1,12 +1,16 @@ import functools import itertools +import warnings +from dataclasses import dataclass, field from types import MappingProxyType +from typing import Callable, Union, List, Dict, Tuple import sympy as sp from pystencils.assignment import Assignment from pystencils.astnodes import Block, Conditional, LoopOverCoordinate, SympyAssignment from pystencils.cpu.vectorization import vectorize +from pystencils.enums import Target, Backend from pystencils.field import Field, FieldType from pystencils.gpucuda.indexing import indexing_creator_from_params from pystencils.simp.assignment_collection import AssignmentCollection @@ -15,29 +19,12 @@ from pystencils.transformations import ( loop_blocking, move_constants_before_loop, remove_conditionals_in_staggered_kernel) -def create_kernel(assignments, - target='cpu', - data_type="double", - iteration_slice=None, - ghost_layers=None, - skip_independence_check=False, - cpu_openmp=False, - cpu_vectorize_info=None, - cpu_blocking=None, - omp_single_loop=True, - gpu_indexing='block', - gpu_indexing_params=MappingProxyType({}), - use_textures_for_interpolation=True, - cpu_prepend_optimizations=[], - use_auto_for_assignments=False, - opencl_queue=None, - opencl_ctx=None): +@dataclass +class CreateKernelConfig: """ - Creates abstract syntax tree (AST) of kernel, using a list of update equations. - - Args: - assignments: can be a single assignment, sequence of assignments or an `AssignmentCollection` - target: 'cpu', 'llvm', 'gpu' or 'opencl' + target: One of Target's enums + backend: One of Backend's enums + function_name: name of the generated function - only important if generated code is written out data_type: data type used for all untyped symbols (i.e. non-fields), can also be a dict from symbol name to type iteration_slice: rectangular subset to iterate over, if not specified the complete non-ghost layer \ @@ -48,15 +35,72 @@ def create_kernel(assignments, skip_independence_check: don't check that loop iterations are independent. This is needed e.g. for periodicity kernel, that access the field outside the iteration bounds. Use with care! cpu_openmp: True or number of threads for OpenMP parallelization, False for no OpenMP - omp_single_loop: if OpenMP is active: whether multiple outer loops are permitted cpu_vectorize_info: a dictionary with keys, 'vector_instruction_set', 'assume_aligned' and 'nontemporal' for documentation of these parameters see vectorize function. Example: '{'instruction_set': 'avx512', 'assume_aligned': True, 'nontemporal':True}' cpu_blocking: a tuple of block sizes or None if no blocking should be applied + omp_single_loop: if OpenMP is active: whether multiple outer loops are permitted gpu_indexing: either 'block' or 'line' , or custom indexing class, see `AbstractIndexing` gpu_indexing_params: dict with indexing parameters (constructor parameters of indexing class) e.g. for 'block' one can specify '{'block_size': (20, 20, 10) }' + use_textures_for_interpolation: cpu_prepend_optimizations: list of extra optimizations to perform first on the AST + use_auto_for_assignments: + opencl_queue: + opencl_ctx: + index_fields: list of index fields, i.e. 1D fields with struct data type. If not None, `create_index_kernel` + instead of `create_domain_kernel` is used. + coordinate_names: name of the coordinate fields in the struct data type + """ + target: Target = Target.CPU + backend: Backend = None + function_name: str = 'kernel' + data_type: Union[str, dict] = 'double' + iteration_slice: Tuple = None + ghost_layers: Union[bool, int, List[Tuple[int]]] = None + skip_independence_check: bool = False + cpu_openmp: bool = False + cpu_vectorize_info: Dict = None + cpu_blocking: Tuple[int] = None + omp_single_loop: bool = True + gpu_indexing: str = 'block' + gpu_indexing_params: MappingProxyType = field(default=MappingProxyType({})) + use_textures_for_interpolation: bool = True + cpu_prepend_optimizations: List[Callable] = field(default_factory=list) + use_auto_for_assignments: bool = False + opencl_queue: ... = None + opencl_ctx: ... = None + index_fields: List[Field] = None + coordinate_names: Tuple[str, ...] = ('x', 'y', 'z') + + def __post_init__(self): + # ---- Legacy parameters + if isinstance(self.target, str): + new_target = Target[self.target.upper()] + warnings.warn(f'Target "{self.target}" as str is deprecated. Use {new_target} instead', + category=DeprecationWarning) + self.target = new_target + # ---- Auto Backend + if not self.backend: + if self.target == Target.CPU: + self.backend = Backend.C + elif self.target == Target.GPU: + self.backend = Backend.CUDA + elif self.target == Target.OPENCL: + self.backend = Backend.OPENCL + else: + raise NotImplementedError(f'Target {self.target} has no default backend') + + +def create_kernel(assignments: Union[Assignment, List[Assignment], AssignmentCollection, List[Conditional]], *, + config: CreateKernelConfig = None, **kwargs): + """ + Creates abstract syntax tree (AST) of kernel, using a list of update equations. + This function forms the general API and delegates the kernel creation to others depending on the CreateKernelConfig. + Args: + assignments: can be a single assignment, sequence of assignments or an `AssignmentCollection` + config: CreateKernelConfig which includes the needed configuration + kwargs: Arguments for updating the config Returns: abstract syntax tree (AST) object, that can either be printed as source code with `show_code` or @@ -67,8 +111,8 @@ def create_kernel(assignments, >>> import numpy as np >>> s, d = ps.fields('s, d: [2D]') >>> assignment = ps.Assignment(d[0,0], s[0, 1] + s[0, -1] + s[1, 0] + s[-1, 0]) - >>> ast = ps.create_kernel(assignment, target='cpu', cpu_openmp=True) - >>> kernel = ast.compile() + >>> kernel_ast = ps.create_kernel(assignment, config=ps.CreateKernelConfig(cpu_openmp=True)) + >>> kernel = kernel_ast.compile() >>> d_arr = np.zeros([5, 5]) >>> kernel(d=d_arr, s=np.ones([5, 5])) >>> d_arr @@ -78,10 +122,56 @@ def create_kernel(assignments, [0., 4., 4., 4., 0.], [0., 0., 0., 0., 0.]]) """ + # ---- Updating configuration from kwargs + if not config: + config = CreateKernelConfig(**kwargs) + else: + for k, v in kwargs.items(): + if not hasattr(config, k): + raise KeyError(f'{v} is not a valid kwarg. Please look in CreateKernelConfig for valid settings') + setattr(config, k, v) + # ---- Normalizing parameters if isinstance(assignments, Assignment): assignments = [assignments] assert assignments, "Assignments must not be empty!" + + if config.index_fields: + return create_indexed_kernel(assignments, config=config) + else: + return create_domain_kernel(assignments, config=config) + + +def create_domain_kernel(assignments: List[Assignment], *, config: CreateKernelConfig): + """ + Creates abstract syntax tree (AST) of kernel, using a list of update equations. + + Args: + assignments: can be a single assignment, sequence of assignments or an `AssignmentCollection` + config: CreateKernelConfig which includes the needed configuration + + Returns: + abstract syntax tree (AST) object, that can either be printed as source code with `show_code` or + can be compiled with through its 'compile()' member + + Example: + >>> import pystencils as ps + >>> import numpy as np + >>> s, d = ps.fields('s, d: [2D]') + >>> assignment = ps.Assignment(d[0,0], s[0, 1] + s[0, -1] + s[1, 0] + s[-1, 0]) + >>> config = ps.CreateKernelConfig(cpu_openmp=True) + >>> kernel_ast = ps.kernelcreation.create_domain_kernel([assignment], config=config) + >>> kernel = kernel_ast.compile() + >>> d_arr = np.zeros([5, 5]) + >>> kernel(d=d_arr, s=np.ones([5, 5])) + >>> d_arr + array([[0., 0., 0., 0., 0.], + [0., 4., 4., 4., 0.], + [0., 4., 4., 4., 0.], + [0., 4., 4., 4., 0.], + [0., 0., 0., 0., 0.]]) + """ + # ---- Normalizing parameters split_groups = () if isinstance(assignments, AssignmentCollection): if 'split_groups' in assignments.simplification_hints: @@ -89,71 +179,68 @@ def create_kernel(assignments, assignments = assignments.all_assignments # ---- Creating ast - if target == 'cpu': - from pystencils.cpu import create_kernel - from pystencils.cpu import add_openmp - ast = create_kernel(assignments, type_info=data_type, split_groups=split_groups, - iteration_slice=iteration_slice, ghost_layers=ghost_layers, - skip_independence_check=skip_independence_check) - for optimization in cpu_prepend_optimizations: - optimization(ast) - omp_collapse = None - if cpu_blocking: - omp_collapse = loop_blocking(ast, cpu_blocking) - if cpu_openmp: - add_openmp(ast, num_threads=cpu_openmp, collapse=omp_collapse, assume_single_outer_loop=omp_single_loop) - if cpu_vectorize_info: - if cpu_vectorize_info is True: - vectorize(ast) - elif isinstance(cpu_vectorize_info, dict): - vectorize(ast, **cpu_vectorize_info) - if cpu_openmp and cpu_blocking and 'nontemporal' in cpu_vectorize_info and \ - cpu_vectorize_info['nontemporal'] and 'cachelineZero' in ast.instruction_set: - # This condition is stricter than it needs to be: if blocks along the fastest axis start on a - # cache line boundary, it's okay. But we cannot determine that here. - # We don't need to disallow OpenMP collapsing because it is never applied to the inner loop. - raise ValueError("Blocking cannot be combined with cacheline-zeroing") - else: - raise ValueError("Invalid value for cpu_vectorize_info") - elif target == 'llvm': - from pystencils.llvm import create_kernel - ast = create_kernel(assignments, type_info=data_type, split_groups=split_groups, - iteration_slice=iteration_slice, ghost_layers=ghost_layers) - elif target == 'gpu' or target == 'opencl': - from pystencils.gpucuda import create_cuda_kernel - ast = create_cuda_kernel(assignments, type_info=data_type, - indexing_creator=indexing_creator_from_params(gpu_indexing, gpu_indexing_params), - iteration_slice=iteration_slice, ghost_layers=ghost_layers, - skip_independence_check=skip_independence_check, - use_textures_for_interpolation=use_textures_for_interpolation) - if target == 'opencl': + ast = None + if config.target == Target.CPU: + if config.backend == Backend.C: + from pystencils.cpu import add_openmp, create_kernel + ast = create_kernel(assignments, function_name=config.function_name, type_info=config.data_type, + split_groups=split_groups, + iteration_slice=config.iteration_slice, ghost_layers=config.ghost_layers, + skip_independence_check=config.skip_independence_check) + for optimization in config.cpu_prepend_optimizations: + optimization(ast) + omp_collapse = None + if config.cpu_blocking: + omp_collapse = loop_blocking(ast, config.cpu_blocking) + if config.cpu_openmp: + add_openmp(ast, num_threads=config.cpu_openmp, collapse=omp_collapse, + assume_single_outer_loop=config.omp_single_loop) + if config.cpu_vectorize_info: + if config.cpu_vectorize_info is True: + vectorize(ast) + elif isinstance(config.cpu_vectorize_info, dict): + vectorize(ast, **config.cpu_vectorize_info) + if config.cpu_openmp and config.cpu_blocking and 'nontemporal' in config.cpu_vectorize_info and \ + config.cpu_vectorize_info['nontemporal'] and 'cachelineZero' in ast.instruction_set: + # This condition is stricter than it needs to be: if blocks along the fastest axis start on a + # cache line boundary, it's okay. But we cannot determine that here. + # We don't need to disallow OpenMP collapsing because it is never applied to the inner loop. + raise ValueError("Blocking cannot be combined with cacheline-zeroing") + else: + raise ValueError("Invalid value for cpu_vectorize_info") + elif config.backend == Backend.LLVM: + from pystencils.llvm import create_kernel + ast = create_kernel(assignments, function_name=config.function_name, type_info=config.data_type, + split_groups=split_groups, iteration_slice=config.iteration_slice, + ghost_layers=config.ghost_layers) + elif config.target == Target.GPU or config.target == Target.OPENCL: + if config.backend == Backend.CUDA or config.backend == Backend.OPENCL: + from pystencils.gpucuda import create_cuda_kernel + ast = create_cuda_kernel(assignments, function_name=config.function_name, type_info=config.data_type, + indexing_creator=indexing_creator_from_params(config.gpu_indexing, + config.gpu_indexing_params), + iteration_slice=config.iteration_slice, ghost_layers=config.ghost_layers, + skip_independence_check=config.skip_independence_check, + use_textures_for_interpolation=config.use_textures_for_interpolation) + if config.backend == Backend.OPENCL: from pystencils.opencl.opencljit import make_python_function - ast._backend = 'opencl' - ast.compile = functools.partial(make_python_function, ast, opencl_queue, opencl_ctx) - ast._target = 'opencl' - ast._backend = 'opencl' - return ast - else: - raise ValueError(f"Unknown target {target}. Has to be one of 'cpu', 'gpu' or 'llvm' ") + ast._backend = config.backend + ast.compile = functools.partial(make_python_function, ast, config.opencl_queue, config.opencl_ctx) + ast._target = config.target + ast._backend = config.backend - if use_auto_for_assignments: + if not ast: + raise NotImplementedError( + f'{config.target} together with {config.backend} is not supported by `create_domain_kernel`') + + if config.use_auto_for_assignments: for a in ast.atoms(SympyAssignment): a.use_auto = True return ast -def create_indexed_kernel(assignments, - index_fields, - target='cpu', - data_type="double", - coordinate_names=('x', 'y', 'z'), - cpu_openmp=True, - gpu_indexing='block', - gpu_indexing_params=MappingProxyType({}), - use_textures_for_interpolation=True, - opencl_queue=None, - opencl_ctx=None): +def create_indexed_kernel(assignments: List[Assignment], *, config: CreateKernelConfig): """ Similar to :func:`create_kernel`, but here not all cells of a field are updated but only cells with coordinates which are stored in an index field. This traversal method can e.g. be used for boundary handling. @@ -163,8 +250,13 @@ def create_indexed_kernel(assignments, 'coordinate_names' parameter. The struct can have also other fields that can be read and written in the kernel, for example boundary parameters. - index_fields: list of index fields, i.e. 1D fields with struct data type - coordinate_names: name of the coordinate fields in the struct data type + Args: + assignments: can be a single assignment, sequence of assignments or an `AssignmentCollection` + config: CreateKernelConfig which includes the needed configuration + + Returns: + abstract syntax tree (AST) object, that can either be printed as source code with `show_code` or + can be compiled with through its 'compile()' member Example: >>> import pystencils as ps @@ -178,8 +270,9 @@ def create_indexed_kernel(assignments, >>> # Additional values stored in index field can be accessed in the kernel as well >>> s, d = ps.fields('s, d: [2D]') >>> assignment = ps.Assignment(d[0,0], 2 * s[0, 1] + 2 * s[1, 0] + idx_field('val')) - >>> ast = create_indexed_kernel(assignment, [idx_field], coordinate_names=('x', 'y')) - >>> kernel = ast.compile() + >>> config = ps.CreateKernelConfig(index_fields=[idx_field], coordinate_names=('x', 'y')) + >>> kernel_ast = ps.create_indexed_kernel([assignment], config=config) + >>> kernel = kernel_ast.compile() >>> d_arr = np.zeros([5, 5]) >>> kernel(s=np.ones([5, 5]), d=d_arr, idx=index_arr) >>> d_arr @@ -189,41 +282,36 @@ def create_indexed_kernel(assignments, [0. , 0. , 0. , 4.3, 0. ], [0. , 0. , 0. , 0. , 0. ]]) """ - if isinstance(assignments, Assignment): - assignments = [assignments] - elif isinstance(assignments, AssignmentCollection): - assignments = assignments.all_assignments - if target == 'cpu': - from pystencils.cpu import create_indexed_kernel - from pystencils.cpu import add_openmp - ast = create_indexed_kernel(assignments, index_fields=index_fields, type_info=data_type, - coordinate_names=coordinate_names) - if cpu_openmp: - add_openmp(ast, num_threads=cpu_openmp) - return ast - elif target == 'llvm': - raise NotImplementedError("Indexed kernels are not yet supported in LLVM backend") - elif target == 'gpu' or target == 'opencl': - from pystencils.gpucuda import created_indexed_cuda_kernel - idx_creator = indexing_creator_from_params(gpu_indexing, gpu_indexing_params) - ast = created_indexed_cuda_kernel(assignments, - index_fields, - type_info=data_type, - coordinate_names=coordinate_names, - indexing_creator=idx_creator, - use_textures_for_interpolation=use_textures_for_interpolation) - if target == 'opencl': - from pystencils.opencl.opencljit import make_python_function - ast._backend = 'opencl' - ast.compile = functools.partial(make_python_function, ast, opencl_queue, opencl_ctx) - ast._target = 'opencl' - ast._backend = 'opencl' - return ast - else: - raise ValueError(f"Unknown target {target}. Has to be either 'cpu' or 'gpu'") + ast = None + if config.target == Target.CPU and config.backend == Backend.C: + from pystencils.cpu import add_openmp, create_indexed_kernel + ast = create_indexed_kernel(assignments, index_fields=config.index_fields, type_info=config.data_type, + coordinate_names=config.coordinate_names) + if config.cpu_openmp: + add_openmp(ast, num_threads=config.cpu_openmp) + elif config.target == Target.GPU or config.target == Target.OPENCL: + if config.backend == Backend.CUDA or config.backend == Backend.OPENCL: + from pystencils.gpucuda import created_indexed_cuda_kernel + idx_creator = indexing_creator_from_params(config.gpu_indexing, config.gpu_indexing_params) + ast = created_indexed_cuda_kernel(assignments, + config.index_fields, + type_info=config.data_type, + coordinate_names=config.coordinate_names, + indexing_creator=idx_creator, + use_textures_for_interpolation=config.use_textures_for_interpolation) + if config.backend == Backend.OPENCL: + from pystencils.opencl.opencljit import make_python_function + ast._backend = config.backend + ast.compile = functools.partial(make_python_function, ast, config.opencl_queue, config.opencl_ctx) + ast._target = config.target + ast._backend = config.backend + + if not ast: + raise NotImplementedError(f'Indexed kernels are not yet supported for {config.target} with {config.backend}') + return ast -def create_staggered_kernel(assignments, target='cpu', gpu_exclusive_conditions=False, **kwargs): +def create_staggered_kernel(assignments, target: Target = Target.CPU, gpu_exclusive_conditions=False, **kwargs): """Kernel that updates a staggered field. .. image:: /img/staggered_grid.svg @@ -237,7 +325,7 @@ def create_staggered_kernel(assignments, target='cpu', gpu_exclusive_conditions= regular fields are passed through to `create_kernel`. Multiple different staggered fields can be used, but they all need to use the same stencil (i.e. the same number of staggered points) and shape. - target: 'cpu', 'llvm' or 'gpu' + target: 'CPU' or 'GPU' gpu_exclusive_conditions: disable the use of multiple conditionals inside the loop. The outer layers are then handled in an else branch. kwargs: passed directly to create_kernel, iteration_slice and ghost_layers parameters are not allowed @@ -331,7 +419,7 @@ def create_staggered_kernel(assignments, target='cpu', gpu_exclusive_conditions= [SympyAssignment(s.lhs, s.rhs) for s in subexpressions if hasattr(s, 'lhs')] + \ [last_conditional] - if target == 'cpu': + if target == Target.CPU: from pystencils.cpu import create_kernel as create_kernel_cpu ast = create_kernel_cpu(final_assignments, ghost_layers=ghost_layers, omp_single_loop=False, **kwargs) else: diff --git a/pystencils/llvm/kernelcreation.py b/pystencils/llvm/kernelcreation.py index 57e5b73876b643196f5529d05df41a11a1ef01e5..c5501f437495c1205f784f2c698cd0a0593314d2 100644 --- a/pystencils/llvm/kernelcreation.py +++ b/pystencils/llvm/kernelcreation.py @@ -1,9 +1,10 @@ +from pystencils.enums import Target, Backend from pystencils.llvm.llvmjit import make_python_function from pystencils.transformations import insert_casts def create_kernel(assignments, function_name="kernel", type_info=None, split_groups=(), - iteration_slice=None, ghost_layers=None, target='cpu'): + iteration_slice=None, ghost_layers=None, target=Target.CPU): """ Creates an abstract syntax tree for a kernel function, by taking a list of update rules. @@ -25,20 +26,19 @@ def create_kernel(assignments, function_name="kernel", type_info=None, split_gro :return: :class:`pystencils.ast.KernelFunction` node """ - if target == 'cpu': + if target == Target.CPU: from pystencils.cpu import create_kernel code = create_kernel(assignments, function_name, type_info, split_groups, iteration_slice, ghost_layers) - code._backend = 'llvm' - elif target == 'gpu': + elif target == Target.GPU: from pystencils.gpucuda.kernelcreation import create_cuda_kernel code = create_cuda_kernel(assignments, function_name, type_info, iteration_slice=iteration_slice, ghost_layers=ghost_layers) - code._backend = 'llvm_gpu' else: - NotImplementedError() + NotImplementedError(f'{target} is not implemented for LLVM kernel creation') + code._backend = Backend.LLVM code.body = insert_casts(code.body) code._compile_function = make_python_function diff --git a/pystencils/llvm/llvm.py b/pystencils/llvm/llvm.py index a0de12689d620abefbd35e168bdac61f44544462..f23e2ca87ccd3a5dc6c472555159a199479a3109 100644 --- a/pystencils/llvm/llvm.py +++ b/pystencils/llvm/llvm.py @@ -6,6 +6,7 @@ import sympy as sp from sympy import Indexed, S from sympy.printing.printer import Printer +from pystencils import Target from pystencils.assignment import Assignment from pystencils.data_types import ( collate_types, create_composite_type_from_string, create_type, get_type_of_expression, @@ -39,7 +40,7 @@ def _call_sreg(builder, name): return builder.call(fn, ()) -def generate_llvm(ast_node, module=None, builder=None, target='cpu'): +def generate_llvm(ast_node, module=None, builder=None, target=Target.CPU): """Prints the ast as llvm code.""" if module is None: module = lc.Module() @@ -53,7 +54,7 @@ def generate_llvm(ast_node, module=None, builder=None, target='cpu'): class LLVMPrinter(Printer): """Convert expressions to LLVM IR""" - def __init__(self, module, builder, fn=None, target='cpu', *args, **kwargs): + def __init__(self, module, builder, fn=None, target=Target.CPU, *args, **kwargs): self.func_arg_map = kwargs.pop("func_arg_map", {}) super(LLVMPrinter, self).__init__(*args, **kwargs) self.fp_type = ir.DoubleType() @@ -191,7 +192,7 @@ class LLVMPrinter(Printer): parameter_type = [] parameters = func.get_parameters() for parameter in parameters: - parameter_type.append(to_llvm_type(parameter.symbol.dtype, nvvm_target=self.target == 'gpu')) + parameter_type.append(to_llvm_type(parameter.symbol.dtype, nvvm_target=self.target == Target.GPU)) func_type = ir.FunctionType(return_type, tuple(parameter_type)) name = func.function_name fn = ir.Function(self.module, func_type, name) @@ -209,7 +210,7 @@ class LLVMPrinter(Printer): self._print(func.body) self.builder.ret_void() self.fn = fn - if self.target == 'gpu': + if self.target == Target.GPU: set_cuda_kernel(fn) return fn @@ -328,7 +329,7 @@ class LLVMPrinter(Printer): self.builder.branch(after_block) self.builder.position_at_end(false_block) - phi = self.builder.phi(to_llvm_type(get_type_of_expression(piece), nvvm_target=self.target == 'gpu')) + phi = self.builder.phi(to_llvm_type(get_type_of_expression(piece), nvvm_target=self.target == Target.GPU)) for (val, block) in phi_data: phi.add_incoming(val, block) return phi diff --git a/pystencils/llvm/llvmjit.py b/pystencils/llvm/llvmjit.py index 2a9f698aa64ae4379af697c2518edcf19018315b..9e48b36bb8689c41774420c1cf250bd7d2602e44 100644 --- a/pystencils/llvm/llvmjit.py +++ b/pystencils/llvm/llvmjit.py @@ -9,6 +9,7 @@ import llvmlite.ir as ir import numpy as np from pystencils.data_types import create_composite_type_from_string +from pystencils.enums import Target from pystencils.field import FieldType from ..data_types import StructType, ctypes_from_llvm, to_ctypes @@ -102,7 +103,7 @@ def make_python_function_incomplete_params(kernel_function_node, argument_dict, def generate_and_jit(ast): - target = 'gpu' if ast._backend == 'llvm_gpu' else 'cpu' + target = ast.target gen = generate_llvm(ast, target=target) if isinstance(gen, ir.Module): return compile_llvm(gen, target, ast) @@ -110,7 +111,9 @@ def generate_and_jit(ast): return compile_llvm(gen.module, target, ast) -def make_python_function(ast, argument_dict={}, func=None): +def make_python_function(ast, argument_dict=None, func=None): + if argument_dict is None: + argument_dict = {} if func is None: jit = generate_and_jit(ast) func = jit.get_function_ptr(ast.function_name) @@ -122,8 +125,8 @@ def make_python_function(ast, argument_dict={}, func=None): return lambda: func(*args) -def compile_llvm(module, target='cpu', ast=None): - jit = CudaJit(ast) if target == "gpu" else Jit() +def compile_llvm(module, target=Target.CPU, ast=None): + jit = CudaJit(ast) if target == Target.GPU else Jit() jit.parse(module) jit.optimize() jit.compile() diff --git a/pystencils/opencl/opencljit.py b/pystencils/opencl/opencljit.py index a33f51c07b51cbac752e12b95c5be78f7060dd08..5fb14a5adbfa6374d5cff0b22197d3f93736550f 100644 --- a/pystencils/opencl/opencljit.py +++ b/pystencils/opencl/opencljit.py @@ -46,7 +46,7 @@ def clear_global_ctx(): def make_python_function(kernel_function_node, opencl_queue, opencl_ctx, argument_dict=None, custom_backend=None): """ Creates a **OpenCL** kernel function from an abstract syntax tree which - was created for the ``target='gpu'`` e.g. by :func:`pystencils.gpucuda.create_cuda_kernel` + was created for the ``target='Target.GPU'`` e.g. by :func:`pystencils.gpucuda.create_cuda_kernel` or :func:`pystencils.gpucuda.created_indexed_cuda_kernel` Args: diff --git a/pystencils/rng.py b/pystencils/rng.py index ec1d6214797a6078d40a8e26320d9c160e6a727f..513792a9631d7a4bb585d63a4eb481fcd241871a 100644 --- a/pystencils/rng.py +++ b/pystencils/rng.py @@ -5,6 +5,7 @@ import sympy as sp from pystencils.data_types import TypedSymbol, cast_func from pystencils.astnodes import LoopOverCoordinate from pystencils.backends.cbackend import CustomCodeNode +from pystencils.enums import Backend from pystencils.sympyextensions import fast_subs @@ -54,7 +55,7 @@ class RNGBase(CustomCodeNode): code += f"{vector_instruction_set[r.dtype.base_name] if vector_instruction_set else r.dtype} " + \ f"{r.name};\n" args = [print_arg(a) for a in self.args] + \ - [('&' if dialect == 'opencl' else '') + r.name for r in self.result_symbols] + [('&' if dialect == Backend.OPENCL else '') + r.name for r in self.result_symbols] code += (self._name + "(" + ", ".join(args) + ");\n") return code diff --git a/pystencils_tests/test_abs.py b/pystencils_tests/test_abs.py index 53917bcc60a8b409490c492b8281d90b44003c25..cf71bc04c7f5fb502a3f1e93b72ca8304fcfaadf 100644 --- a/pystencils_tests/test_abs.py +++ b/pystencils_tests/test_abs.py @@ -1,19 +1,20 @@ import sympy -import pystencils +import pystencils as ps from pystencils.data_types import cast_func, create_type def test_abs(): - x, y, z = pystencils.fields('x, y, z: float64[2d]') + x, y, z = ps.fields('x, y, z: float64[2d]') default_int_type = create_type('int64') - assignments = pystencils.AssignmentCollection({ + assignments = ps.AssignmentCollection({ x[0, 0]: sympy.Abs(cast_func(y[0, 0], default_int_type)) }) - ast = pystencils.create_kernel(assignments, target="gpu") - code = pystencils.get_code_str(ast) + config = ps.CreateKernelConfig(target=ps.Target.GPU) + ast = ps.create_kernel(assignments, config=config) + code = ps.get_code_str(ast) print(code) assert 'fabs(' not in code diff --git a/pystencils_tests/test_astnodes.py b/pystencils_tests/test_astnodes.py index a3edc1c2bfb860b2ff967dc74694a27442addb22..385c4e2234f7879d61ef64cb7dbe4961071e09c6 100644 --- a/pystencils_tests/test_astnodes.py +++ b/pystencils_tests/test_astnodes.py @@ -27,8 +27,8 @@ def test_kernel_function(): ast_node = ps.create_kernel(assignments) - assert ast_node.target == 'cpu' - assert ast_node.backend == 'c' + assert ast_node.target == ps.Target.CPU + assert ast_node.backend == ps.Backend.C # symbols_defined and undefined_symbols will always return an emtpy set assert ast_node.symbols_defined == set() assert ast_node.undefined_symbols == set() diff --git a/pystencils_tests/test_basic_usage_llvm.ipynb b/pystencils_tests/test_basic_usage_llvm.ipynb index 623bad6601f64a3f26521df74bb747359ee207ff..1f2d71e0711eb3cf9c429149eadcb2b5bcfc4c9f 100644 --- a/pystencils_tests/test_basic_usage_llvm.ipynb +++ b/pystencils_tests/test_basic_usage_llvm.ipynb @@ -30,7 +30,7 @@ "import numpy as np\n", "import ctypes\n", "from pystencils import Field, Assignment\n", - "from pystencils import create_kernel\n", + "from pystencils import create_kernel, Backend\n", "from pystencils.display_utils import to_dot\n", "\n", "sp.init_printing()" @@ -127,7 +127,7 @@ } ], "source": [ - "ast = create_kernel([update_rule], target='llvm')\n", + "ast = create_kernel([update_rule], backend=Backend.LLVM)\n", "print(str(ast))" ] }, @@ -432,4 +432,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/pystencils_tests/test_boundary.py b/pystencils_tests/test_boundary.py index b5c0f9f975516b840876a293bf9f4e47e6bb8c8f..4dc6439a079606b4536ef3331fa3ca5eeeb0f4aa 100644 --- a/pystencils_tests/test_boundary.py +++ b/pystencils_tests/test_boundary.py @@ -4,9 +4,11 @@ from tempfile import TemporaryDirectory import numpy as np import pytest +import pystencils from pystencils import Assignment, create_kernel from pystencils.boundaries import BoundaryHandling, Dirichlet, Neumann, add_neumann_boundary from pystencils.datahandling import SerialDataHandling +from pystencils.enums import Target from pystencils.slicing import slice_from_direction from pystencils.timeloop import TimeLoop @@ -96,7 +98,7 @@ def test_kernel_vs_copy_boundary(): def test_boundary_gpu(): pytest.importorskip('pycuda') - dh = SerialDataHandling(domain_size=(7, 7), default_target="gpu") + dh = SerialDataHandling(domain_size=(7, 7), default_target=Target.GPU) src = dh.add_array('src') dh.fill("src", 0.0, ghost_layers=True) dh.fill("src", 1.0, ghost_layers=False) @@ -106,10 +108,10 @@ def test_boundary_gpu(): boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)] boundary_handling_cpu = BoundaryHandling(dh, src_cpu.name, boundary_stencil, - name="boundary_handling_cpu", target='cpu') + name="boundary_handling_cpu", target=Target.CPU) boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil, - name="boundary_handling_gpu", target='gpu') + name="boundary_handling_gpu", target=Target.GPU) neumann = Neumann() for d in ('N', 'S', 'W', 'E'): @@ -135,7 +137,7 @@ def test_boundary_utility(): boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)] boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil, - name="boundary_handling", target='cpu') + name="boundary_handling", target=Target.CPU) neumann = Neumann() dirichlet = Dirichlet(2) @@ -180,7 +182,7 @@ def test_add_fix_steps(): boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)] boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil, - name="boundary_handling", target='cpu') + name="boundary_handling", target=pystencils.Target.CPU) neumann = Neumann() for d in ('N', 'S', 'W', 'E'): @@ -201,7 +203,7 @@ def test_boundary_data_setter(): boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)] boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil, - name="boundary_handling", target='cpu') + name="boundary_handling", target=Target.CPU) neumann = Neumann() for d in 'N': diff --git a/pystencils_tests/test_buffer.py b/pystencils_tests/test_buffer.py index 43b14e76e227bbaa8cc0709892fa0adc085460ef..3da6f04155d7d67e9d4573d062c28ad411a4cdd2 100644 --- a/pystencils_tests/test_buffer.py +++ b/pystencils_tests/test_buffer.py @@ -207,10 +207,10 @@ def test_iteration_slices(): dim = src_field.spatial_dimensions # Pack only the leftmost slice, only every second cell - pack_slice = (slice(None, None, 2),) * (dim-1) + (0, ) + pack_slice = (slice(None, None, 2),) * (dim-1) + (0, ) # Fill the entire array with data - src_arr[ (slice(None, None, 1),) * dim] = np.arange(num_cell_values) + src_arr[(slice(None, None, 1),) * dim] = np.arange(num_cell_values) dst_arr.fill(0.0) pack_code = create_kernel(pack_eqs, iteration_slice=pack_slice, data_type={'src_field': src_arr.dtype, 'buffer': buffer.dtype}) diff --git a/pystencils_tests/test_complex_numbers.py b/pystencils_tests/test_complex_numbers.py index 41dc76a40411129c4ee68f0ee42028b57875d71e..9d9f719527deca49e277e86da70bf732384849c7 100644 --- a/pystencils_tests/test_complex_numbers.py +++ b/pystencils_tests/test_complex_numbers.py @@ -47,7 +47,7 @@ SCALAR_DTYPES = ['float32', 'float64'] @pytest.mark.parametrize("assignment, scalar_dtypes", itertools.product(TEST_ASSIGNMENTS, (np.float32,))) -@pytest.mark.parametrize('target', ('cpu', 'gpu')) +@pytest.mark.parametrize('target', (pystencils.Target.CPU, pystencils.Target.GPU)) def test_complex_numbers(assignment, scalar_dtypes, target): ast = pystencils.create_kernel(assignment, target=target, @@ -57,7 +57,7 @@ def test_complex_numbers(assignment, scalar_dtypes, target): print(code) assert "Not supported" not in code - if target == 'gpu': + if target == pystencils.Target.GPU: pytest.importorskip('pycuda') kernel = ast.compile() @@ -93,7 +93,7 @@ SCALAR_DTYPES = ['float64'] @pytest.mark.parametrize("assignment", TEST_ASSIGNMENTS) -@pytest.mark.parametrize('target', ('cpu', 'gpu')) +@pytest.mark.parametrize('target', (pystencils.Target.CPU, pystencils.Target.GPU)) def test_complex_numbers_64(assignment, target): ast = pystencils.create_kernel(assignment, target=target, @@ -103,7 +103,7 @@ def test_complex_numbers_64(assignment, target): print(code) assert "Not supported" not in code - if target == 'gpu': + if target == pystencils.Target.GPU: pytest.importorskip('pycuda') kernel = ast.compile() @@ -111,7 +111,7 @@ def test_complex_numbers_64(assignment, target): @pytest.mark.parametrize('dtype', (np.float32, np.float64)) -@pytest.mark.parametrize('target', ('cpu', 'gpu')) +@pytest.mark.parametrize('target', (pystencils.Target.CPU, pystencils.Target.GPU)) @pytest.mark.parametrize('with_complex_argument', ('with_complex_argument', False)) def test_complex_execution(dtype, target, with_complex_argument): @@ -130,7 +130,7 @@ def test_complex_execution(dtype, target, with_complex_argument): y.center: x.center + a }) - if target == 'gpu': + if target == pystencils.Target.GPU: pytest.importorskip('pycuda') from pycuda.gpuarray import zeros x_arr = zeros((20, 30), complex_dtype) @@ -143,7 +143,7 @@ def test_complex_execution(dtype, target, with_complex_argument): else: kernel(x=x_arr, y=y_arr) - if target == 'gpu': + if target == pystencils.Target.GPU: y_arr = y_arr.get() assert np.allclose(y_arr, 2j+1) diff --git a/pystencils_tests/test_conditional_vec.py b/pystencils_tests/test_conditional_vec.py index c67075418c7c986d7232e805451799f4fd0bf182..1a962d00f8cb92c5f2bf6619307ce17777190c4b 100644 --- a/pystencils_tests/test_conditional_vec.py +++ b/pystencils_tests/test_conditional_vec.py @@ -5,10 +5,12 @@ import pytest import pystencils as ps from pystencils.astnodes import Block, Conditional from pystencils.backends.simd_instruction_sets import get_supported_instruction_sets, get_vector_instruction_set +from pystencils.enums import Target from pystencils.cpu.vectorization import vec_all, vec_any supported_instruction_sets = get_supported_instruction_sets() if get_supported_instruction_sets() else [] + @pytest.mark.parametrize('instruction_set', supported_instruction_sets) @pytest.mark.parametrize('dtype', ('float', 'double')) def test_vec_any(instruction_set, dtype): @@ -16,9 +18,9 @@ def test_vec_any(instruction_set, dtype): width = 4 # we don't know the actual value else: width = get_vector_instruction_set(dtype, instruction_set)['width'] - data_arr = np.zeros((4*width, 4*width), dtype=np.float64 if dtype == 'double' else np.float32) + data_arr = np.zeros((4 * width, 4 * width), dtype=np.float64 if dtype == 'double' else np.float32) - data_arr[3:9, 1:3*width-1] = 1.0 + data_arr[3:9, 1:3 * width - 1] = 1.0 data = ps.fields(f"data: {dtype}[2D]", data=data_arr) c = [ @@ -27,15 +29,15 @@ def test_vec_any(instruction_set, dtype): ps.Assignment(data.center(), 2.0) ])) ] - ast = ps.create_kernel(c, target='cpu', + ast = ps.create_kernel(c, target=ps.Target.CPU, cpu_vectorize_info={'instruction_set': instruction_set}) kernel = ast.compile() kernel(data=data_arr) if instruction_set in ['sve', 'rvv']: # we only know that the first value has changed - np.testing.assert_equal(data_arr[3:9, :3*width-1], 2.0) + np.testing.assert_equal(data_arr[3:9, :3 * width - 1], 2.0) else: - np.testing.assert_equal(data_arr[3:9, :3*width], 2.0) + np.testing.assert_equal(data_arr[3:9, :3 * width], 2.0) @pytest.mark.parametrize('instruction_set', supported_instruction_sets) @@ -45,9 +47,9 @@ def test_vec_all(instruction_set, dtype): width = 1000 # we don't know the actual value, need something guaranteed larger than vector else: width = get_vector_instruction_set(dtype, instruction_set)['width'] - data_arr = np.zeros((4*width, 4*width), dtype=np.float64 if dtype == 'double' else np.float32) + data_arr = np.zeros((4 * width, 4 * width), dtype=np.float64 if dtype == 'double' else np.float32) - data_arr[3:9, 1:3*width-1] = 1.0 + data_arr[3:9, 1:3 * width - 1] = 1.0 data = ps.fields(f"data: {dtype}[2D]", data=data_arr) c = [ @@ -55,7 +57,7 @@ def test_vec_all(instruction_set, dtype): ps.Assignment(data.center(), 2.0) ])) ] - ast = ps.create_kernel(c, target='cpu', + ast = ps.create_kernel(c, target=Target.CPU, cpu_vectorize_info={'instruction_set': instruction_set}) kernel = ast.compile() kernel(data=data_arr) @@ -66,9 +68,9 @@ def test_vec_all(instruction_set, dtype): else: np.testing.assert_equal(data_arr[3:9, :1], 0.0) np.testing.assert_equal(data_arr[3:9, 1:width], 1.0) - np.testing.assert_equal(data_arr[3:9, width:2*width], 2.0) - np.testing.assert_equal(data_arr[3:9, 2*width:3*width-1], 1.0) - np.testing.assert_equal(data_arr[3:9, 3*width-1:], 0.0) + np.testing.assert_equal(data_arr[3:9, width:2 * width], 2.0) + np.testing.assert_equal(data_arr[3:9, 2 * width:3 * width - 1], 1.0) + np.testing.assert_equal(data_arr[3:9, 3 * width - 1:], 0.0) @pytest.mark.skipif(not supported_instruction_sets, reason='cannot detect CPU instruction set') @@ -104,7 +106,7 @@ def test_vec_maskstore(instruction_set, dtype): ps.Assignment(data.center(), 2.0) ])) ] - ast = ps.create_kernel(c, target='cpu', + ast = ps.create_kernel(c, target=Target.CPU, cpu_vectorize_info={'instruction_set': instruction_set}) kernel = ast.compile() kernel(data=data_arr) diff --git a/pystencils_tests/test_create_kernel_backwards_compability.py b/pystencils_tests/test_create_kernel_backwards_compability.py new file mode 100644 index 0000000000000000000000000000000000000000..7aa86b45fa5e9fe72768f7243ed647b0853ccac0 --- /dev/null +++ b/pystencils_tests/test_create_kernel_backwards_compability.py @@ -0,0 +1,30 @@ +import pystencils as ps +import numpy as np + + +def test_create_kernel_backwards_compatibility(): + size = (30, 20) + + src_field_string = np.random.rand(*size) + src_field_enum = np.copy(src_field_string) + src_field_config = np.copy(src_field_string) + dst_field_string = np.zeros(size) + dst_field_enum = np.zeros(size) + dst_field_config = np.zeros(size) + + f = ps.Field.create_from_numpy_array("f", src_field_enum) + d = ps.Field.create_from_numpy_array("d", dst_field_enum) + + jacobi = ps.Assignment(d[0, 0], (f[1, 0] + f[-1, 0] + f[0, 1] + f[0, -1]) / 4) + ast_enum = ps.create_kernel(jacobi, target=ps.Target.CPU).compile() + ast_string = ps.create_kernel(jacobi, target='cpu').compile() + # noinspection PyTypeChecker + ast_config = ps.create_kernel(jacobi, config=ps.CreateKernelConfig(target='cpu')).compile() + ast_enum(f=src_field_enum, d=dst_field_enum) + ast_string(f=src_field_string, d=dst_field_string) + ast_config(f=src_field_config, d=dst_field_config) + + error = np.sum(np.abs(dst_field_enum - dst_field_string)) + np.testing.assert_almost_equal(error, 0.0) + error = np.sum(np.abs(dst_field_enum - dst_field_config)) + np.testing.assert_almost_equal(error, 0.0) diff --git a/pystencils_tests/test_create_kernel_config.py b/pystencils_tests/test_create_kernel_config.py new file mode 100644 index 0000000000000000000000000000000000000000..c36ba483ca9fd9718f284731f648a48777de29e3 --- /dev/null +++ b/pystencils_tests/test_create_kernel_config.py @@ -0,0 +1,17 @@ +import pystencils as ps + + +def test_create_kernel_config(): + c = ps.CreateKernelConfig() + assert c.backend == ps.Backend.C + assert c.target == ps.Target.CPU + + c = ps.CreateKernelConfig(target=ps.Target.GPU) + assert c.backend == ps.Backend.CUDA + + c = ps.CreateKernelConfig(target=ps.Target.OPENCL) + assert c.backend == ps.Backend.OPENCL + + c = ps.CreateKernelConfig(backend=ps.Backend.CUDA) + assert c.target == ps.Target.CPU + assert c.backend == ps.Backend.CUDA diff --git a/pystencils_tests/test_cuda_known_functions.py b/pystencils_tests/test_cuda_known_functions.py index dcdabeaef6934e06b289351127b168d77d803be9..32b7d9b76de939769a47b117d8529aeb5ff3e20f 100644 --- a/pystencils_tests/test_cuda_known_functions.py +++ b/pystencils_tests/test_cuda_known_functions.py @@ -6,6 +6,7 @@ import pystencils from pystencils.astnodes import get_dummy_symbol from pystencils.backends.cuda_backend import CudaSympyPrinter from pystencils.data_types import address_of +from pystencils.enums import Target def test_cuda_known_functions(): @@ -19,7 +20,7 @@ def test_cuda_known_functions(): y.center(): sympy.Function('rsqrtf')(x[0, 0]) }) - ast = pystencils.create_kernel(assignments, 'gpu') + ast = pystencils.create_kernel(assignments, target=Target.GPU) pytest.importorskip('pycuda') pystencils.show_code(ast) kernel = ast.compile() @@ -34,7 +35,7 @@ def test_cuda_but_not_c(): y.center(): sympy.Function('rsqrtf')(x[0, 0]) }) - ast = pystencils.create_kernel(assignments, 'cpu') + ast = pystencils.create_kernel(assignments, target=Target.CPU) pystencils.show_code(ast) @@ -45,5 +46,5 @@ def test_cuda_unknown(): get_dummy_symbol(): sympy.Function('wtf')(address_of(y.center()), 2), }) - ast = pystencils.create_kernel(assignments, 'gpu') + ast = pystencils.create_kernel(assignments, target=Target.GPU) pystencils.show_code(ast) diff --git a/pystencils_tests/test_custom_backends.py b/pystencils_tests/test_custom_backends.py index aa889f339633ff95040642f4a2447282bfd11605..696d1be2772a82de387c5da18376458e35000349 100644 --- a/pystencils_tests/test_custom_backends.py +++ b/pystencils_tests/test_custom_backends.py @@ -7,6 +7,7 @@ import pystencils import pystencils.cpu.cpujit from pystencils.backends.cbackend import CBackend from pystencils.backends.cuda_backend import CudaBackend +from pystencils.enums import Target class ScreamingBackend(CBackend): @@ -29,7 +30,7 @@ def test_custom_backends_cpu(): normal_assignments = pystencils.AssignmentCollection([pystencils.Assignment( z[0, 0], x[0, 0] * sympy.log(x[0, 0] * y[0, 0]))], []) - ast = pystencils.create_kernel(normal_assignments, target='cpu') + ast = pystencils.create_kernel(normal_assignments, target=Target.CPU) pystencils.show_code(ast, ScreamingBackend()) with pytest.raises(CalledProcessError): pystencils.cpu.cpujit.make_python_function(ast, custom_backend=ScreamingBackend()) @@ -45,7 +46,7 @@ def test_custom_backends_gpu(): normal_assignments = pystencils.AssignmentCollection([pystencils.Assignment( z[0, 0], x[0, 0] * sympy.log(x[0, 0] * y[0, 0]))], []) - ast = pystencils.create_kernel(normal_assignments, target='gpu') + ast = pystencils.create_kernel(normal_assignments, target=Target.GPU) pystencils.show_code(ast, ScreamingGpuBackend()) with pytest.raises(pycuda.driver.CompileError): pystencils.gpucuda.cudajit.make_python_function(ast, custom_backend=ScreamingGpuBackend()) diff --git a/pystencils_tests/test_datahandling.py b/pystencils_tests/test_datahandling.py index 9d0798ee86274f22b37ffa21a004bf279a56841a..7004415fb98e25460462fd0d830bcc45af8c6365 100644 --- a/pystencils_tests/test_datahandling.py +++ b/pystencils_tests/test_datahandling.py @@ -8,6 +8,7 @@ import pystencils as ps from pystencils import create_data_handling, create_kernel from pystencils.datahandling.pycuda import PyCudaArrayHandler from pystencils.datahandling.pyopencl import PyOpenClArrayHandler +from pystencils.enums import Target try: import pytest @@ -116,7 +117,7 @@ def synchronization(dh, test_gpu=False): def kernel_execution_jacobi(dh, target): - test_gpu = target == 'gpu' or target == 'opencl' + test_gpu = target == Target.GPU or target == Target.OPENCL dh.add_array('f', gpu=test_gpu) dh.add_array('tmp', gpu=test_gpu) @@ -132,7 +133,7 @@ def kernel_execution_jacobi(dh, target): def jacobi(): dh.fields.tmp.center @= sum(dh.fields.f.neighbors(stencil)) / len(stencil) - kernel = create_kernel(jacobi, target).compile() + kernel = create_kernel(jacobi, target=target).compile() for b in dh.iterate(ghost_layers=1): b['f'].fill(42) dh.run_kernel(kernel) @@ -211,23 +212,23 @@ def test_kernel(): for domain_shape in [(4, 5), (3, 4, 5)]: dh = create_data_handling(domain_size=domain_shape, periodicity=True) assert all(dh.periodicity) - kernel_execution_jacobi(dh, 'cpu') + kernel_execution_jacobi(dh, Target.CPU) reduction(dh) try: import pycuda dh = create_data_handling(domain_size=domain_shape, periodicity=True) - kernel_execution_jacobi(dh, 'gpu') + kernel_execution_jacobi(dh, Target.GPU) except ImportError: pass -@pytest.mark.parametrize('target', ('cpu', 'gpu', 'opencl')) +@pytest.mark.parametrize('target', (Target.CPU, Target.GPU, Target.OPENCL)) def test_kernel_param(target): for domain_shape in [(4, 5), (3, 4, 5)]: - if target == 'gpu': + if target == Target.GPU: pytest.importorskip('pycuda') - if target == 'opencl': + if target == Target.OPENCL: pytest.importorskip('pyopencl') from pystencils.opencl.opencljit import init_globally init_globally() @@ -361,13 +362,13 @@ def test_load_data(): assert np.all(dh.cpu_arrays['dst2']) == 0 -@pytest.mark.parametrize('target', ('gpu', 'opencl')) +@pytest.mark.parametrize('target', (Target.GPU, Target.OPENCL)) def test_array_handler(target): size = (2, 2) - if target == 'gpu': + if target == Target.GPU: pytest.importorskip('pycuda') array_handler = PyCudaArrayHandler() - if target == 'opencl': + if target == Target.OPENCL: pytest.importorskip('pyopencl') import pyopencl as cl from pystencils.opencl.opencljit import init_globally diff --git a/pystencils_tests/test_datahandling_parallel.py b/pystencils_tests/test_datahandling_parallel.py index 9d9b5f0449ae9a0d03666d4b80e90c440707584e..82567fe45bfbd78dadc9a0e3ac037c9c98521525 100644 --- a/pystencils_tests/test_datahandling_parallel.py +++ b/pystencils_tests/test_datahandling_parallel.py @@ -1,5 +1,7 @@ import numpy as np import waLBerla as wlb + +import pystencils from pystencils import make_slice from tempfile import TemporaryDirectory @@ -67,13 +69,13 @@ def test_kernel(): # 3D blocks = wlb.createUniformBlockGrid(blocks=(3, 2, 4), cellsPerBlock=(3, 2, 5), oneBlockPerProcess=False) dh = ParallelDataHandling(blocks) - kernel_execution_jacobi(dh, 'gpu') + kernel_execution_jacobi(dh, pystencils.Target.GPU) reduction(dh) # 2D blocks = wlb.createUniformBlockGrid(blocks=(3, 2, 1), cellsPerBlock=(3, 2, 1), oneBlockPerProcess=False) dh = ParallelDataHandling(blocks, dim=2) - kernel_execution_jacobi(dh, 'gpu') + kernel_execution_jacobi(dh, pystencils.Target.GPU) reduction(dh) @@ -133,7 +135,7 @@ def test_getter_setter(): def test_parallel_datahandling_boundary_conditions(): pytest.importorskip('waLBerla.cuda') - dh = create_data_handling(domain_size=(7, 7), periodicity=True, parallel=True, default_target="gpu") + dh = create_data_handling(domain_size=(7, 7), periodicity=True, parallel=True, default_target=pystencils.Target.GPU) src = dh.add_array('src') src2 = dh.add_array('src2') dh.fill("src", 0.0, ghost_layers=True) @@ -144,10 +146,10 @@ def test_parallel_datahandling_boundary_conditions(): boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)] boundary_handling_cpu = BoundaryHandling(dh, src_cpu.name, boundary_stencil, - name="boundary_handling_cpu", target='cpu') + name="boundary_handling_cpu", target=pystencils.Target.CPU) boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil, - name="boundary_handling_gpu", target='gpu') + name="boundary_handling_gpu", target=pystencils.Target.GPU) neumann = Neumann() for d in ('N', 'S', 'W', 'E'): diff --git a/pystencils_tests/test_fast_approximation.py b/pystencils_tests/test_fast_approximation.py index c596bed1a49ec59f568b832c7d583cff1418f5f8..5b7245af9b12a1127e67ede6e4ce231efd73e078 100644 --- a/pystencils_tests/test_fast_approximation.py +++ b/pystencils_tests/test_fast_approximation.py @@ -13,7 +13,7 @@ def test_fast_sqrt(): assert len(insert_fast_sqrts(expr).atoms(fast_sqrt)) == 1 assert len(insert_fast_sqrts([expr])[0].atoms(fast_sqrt)) == 1 - ast_gpu = ps.create_kernel(ps.Assignment(g[0, 0], insert_fast_sqrts(expr)), target='gpu') + ast_gpu = ps.create_kernel(ps.Assignment(g[0, 0], insert_fast_sqrts(expr)), target=ps.Target.GPU) ast_gpu.compile() code_str = ps.get_code_str(ast_gpu) assert '__fsqrt_rn' in code_str @@ -23,7 +23,7 @@ def test_fast_sqrt(): ac = ps.AssignmentCollection([expr], []) assert len(insert_fast_sqrts(ac).main_assignments[0].atoms(fast_inv_sqrt)) == 1 - ast_gpu = ps.create_kernel(insert_fast_sqrts(ac), target='gpu') + ast_gpu = ps.create_kernel(insert_fast_sqrts(ac), target=ps.Target.GPU) ast_gpu.compile() code_str = ps.get_code_str(ast_gpu) assert '__frsqrt_rn' in code_str @@ -38,7 +38,7 @@ def test_fast_divisions(): expr = 1 / f[0, 0] * 2 / f[0, 1] assert len(insert_fast_divisions(expr).atoms(fast_division)) == 1 - ast = ps.create_kernel(ps.Assignment(g[0, 0], insert_fast_divisions(expr)), target='gpu') + ast = ps.create_kernel(ps.Assignment(g[0, 0], insert_fast_divisions(expr)), target=ps.Target.GPU) ast.compile() code_str = ps.get_code_str(ast) assert '__fdividef' in code_str diff --git a/pystencils_tests/test_fvm.py b/pystencils_tests/test_fvm.py index 42127cc76971b9cda33297c52ad8b5de93ecf094..ebd9287d23a83b9d2221e5fb385ef64ab41e6b04 100644 --- a/pystencils_tests/test_fvm.py +++ b/pystencils_tests/test_fvm.py @@ -12,7 +12,7 @@ def advection_diffusion(dim: int): elif dim == 3: L = (16, 16, 16) - dh = ps.create_data_handling(domain_size=L, periodicity=True, default_target='cpu') + dh = ps.create_data_handling(domain_size=L, periodicity=True, default_target=ps.Target.CPU) n_field = dh.add_array('n', values_per_cell=1) j_field = dh.add_array('j', values_per_cell=3 ** dim // 2, field_type=ps.FieldType.STAGGERED_FLUX) @@ -203,7 +203,7 @@ def VOF2(j: ps.field.Field, v: ps.field.Field, Ï: ps.field.Field, simplify=True @pytest.mark.parametrize("dim", [2, 3]) def test_advection(dim): L = (8,) * dim - dh = ps.create_data_handling(L, periodicity=True, default_target='cpu') + dh = ps.create_data_handling(L, periodicity=True, default_target=ps.Target.CPU) c = dh.add_array('c', values_per_cell=1) j = dh.add_array('j', values_per_cell=3 ** dh.dim // 2, field_type=ps.FieldType.STAGGERED_FLUX) u = dh.add_array('u', values_per_cell=dh.dim) @@ -235,7 +235,7 @@ def test_ek(stencil): # data structures - dh = ps.create_data_handling(L, periodicity=True, default_target='cpu') + dh = ps.create_data_handling(L, periodicity=True, default_target=ps.Target.CPU) c = dh.add_array('c', values_per_cell=1) j = dh.add_array('j', values_per_cell=int(stencil[-1]) // 2, field_type=ps.FieldType.STAGGERED_FLUX) Phi = dh.add_array('Φ', values_per_cell=1) @@ -288,7 +288,7 @@ def test_ek(stencil): @pytest.mark.parametrize("derivative", [0, 1]) def test_flux_stencil(stencil, derivative): L = (40, ) * int(stencil[1]) - dh = ps.create_data_handling(L, periodicity=True, default_target='cpu') + dh = ps.create_data_handling(L, periodicity=True, default_target=ps.Target.CPU) c = dh.add_array('c', values_per_cell=1) j = dh.add_array('j', values_per_cell=int(stencil[3:]) // 2, field_type=ps.FieldType.STAGGERED_FLUX) @@ -311,7 +311,7 @@ def test_flux_stencil(stencil, derivative): @pytest.mark.parametrize("stencil", ["D2Q5", "D2Q9", "D3Q7", "D3Q19", "D3Q27"]) def test_source_stencil(stencil): L = (40, ) * int(stencil[1]) - dh = ps.create_data_handling(L, periodicity=True, default_target='cpu') + dh = ps.create_data_handling(L, periodicity=True, default_target=ps.Target.CPU) c = dh.add_array('c', values_per_cell=1) j = dh.add_array('j', values_per_cell=int(stencil[3:]) // 2, field_type=ps.FieldType.STAGGERED_FLUX) diff --git a/pystencils_tests/test_interpolation.py b/pystencils_tests/test_interpolation.py index 257d4af802995dd43e1ca29651f31c0acd5d85cf..b5383a330b362c1637d128e0f8978afd77104f5f 100644 --- a/pystencils_tests/test_interpolation.py +++ b/pystencils_tests/test_interpolation.py @@ -126,7 +126,8 @@ def test_rotate_interpolation_gpu(dtype, address_mode, use_textures): y_f.center(): LinearInterpolator(x_f, address_mode=address_mode).at(transformed) }) print(assignments) - ast = pystencils.create_kernel(assignments, target='gpu', use_textures_for_interpolation=use_textures) + ast = pystencils.create_kernel(assignments, target=pystencils.Target.GPU, + use_textures_for_interpolation=use_textures) print(ast) print(pystencils.show_code(ast)) kernel = ast.compile() @@ -171,7 +172,8 @@ def test_shift_interpolation_gpu(address_mode, dtype, use_textures): y_f.center(): LinearInterpolator(x_f, address_mode=address_mode).at(transformed) }) # print(assignments) - ast = pystencils.create_kernel(assignments, target='gpu', use_textures_for_interpolation=use_textures) + ast = pystencils.create_kernel(assignments, target=pystencils.Target.GPU, + use_textures_for_interpolation=use_textures) # print(ast) print(pystencils.show_code(ast)) kernel = ast.compile() @@ -207,7 +209,7 @@ def test_rotate_interpolation_size_change(address_mode): @pytest.mark.parametrize('address_mode, target', - itertools.product(['border', 'wrap', 'clamp', 'mirror'], ['cpu'])) + itertools.product(['border', 'wrap', 'clamp', 'mirror'], [pystencils.Target.CPU])) def test_field_interpolated(address_mode, target): x_f, y_f = pystencils.fields('x,y: float64 [2d]') diff --git a/pystencils_tests/test_jacobi_cbackend.py b/pystencils_tests/test_jacobi_cbackend.py index 6d86ecb05f920f7a6c54b018ea5dd3508172b727..2ad6c007aa730a9c8eecd73b33f9d34ce9930395 100644 --- a/pystencils_tests/test_jacobi_cbackend.py +++ b/pystencils_tests/test_jacobi_cbackend.py @@ -4,6 +4,7 @@ from pystencils import get_code_obj from pystencils.astnodes import Block, KernelFunction, SympyAssignment from pystencils.cpu import make_python_function from pystencils.field import Field +from pystencils.enums import Target, Backend from pystencils.transformations import ( make_loop_over_domain, move_constants_before_loop, resolve_field_accesses) @@ -22,7 +23,7 @@ def test_jacobi_fixed_field_size(): jacobi = SympyAssignment(d[0, 0], (f[1, 0] + f[-1, 0] + f[0, 1] + f[0, -1]) / 4) body = Block([jacobi]) loop_node, gl_info = make_loop_over_domain(body) - ast_node = KernelFunction(loop_node, 'cpu', 'c', make_python_function, ghost_layers=gl_info) + ast_node = KernelFunction(loop_node, Target.CPU, Backend.C, make_python_function, ghost_layers=gl_info) resolve_field_accesses(ast_node) move_constants_before_loop(ast_node) @@ -48,7 +49,7 @@ def test_jacobi_variable_field_size(): jacobi = SympyAssignment(d[0, 0, 0], (f[1, 0, 0] + f[-1, 0, 0] + f[0, 1, 0] + f[0, -1, 0]) / 4) body = Block([jacobi]) loop_node, gl_info = make_loop_over_domain(body) - ast_node = KernelFunction(loop_node, 'cpu', 'c', make_python_function, ghost_layers=gl_info) + ast_node = KernelFunction(loop_node, Target.CPU, Backend.C, make_python_function, ghost_layers=gl_info) resolve_field_accesses(ast_node) move_constants_before_loop(ast_node) @@ -57,13 +58,13 @@ def test_jacobi_variable_field_size(): dst_field_c = np.zeros(size) dst_field_py = np.zeros(size) - for x in range(1, size[0]-1): - for y in range(1, size[1]-1): - for z in range(1, size[2]-1): + for x in range(1, size[0] - 1): + for y in range(1, size[1] - 1): + for z in range(1, size[2] - 1): dst_field_py[x, y, z] = 0.25 * (src_field_py[x - 1, y, z] + src_field_py[x + 1, y, z] + src_field_py[x, y - 1, z] + src_field_py[x, y + 1, z]) kernel = ast_node.compile() kernel(f=src_field_c, d=dst_field_c) - error = np.sum(np.abs(dst_field_py-dst_field_c)) + error = np.sum(np.abs(dst_field_py - dst_field_c)) np.testing.assert_allclose(error, 0.0, atol=1e-13) diff --git a/pystencils_tests/test_llvm.py b/pystencils_tests/test_llvm.py index 28b38fe98a948ddcbf06db3b572f744960ec7980..d1bcf4301444b194d6a604ee544fe45e0546f8ff 100644 --- a/pystencils_tests/test_llvm.py +++ b/pystencils_tests/test_llvm.py @@ -4,7 +4,7 @@ try: from pystencils.llvm.llvmjit import generate_and_jit from pystencils.llvm import create_kernel, make_python_function from pystencils.cpu.cpujit import get_llc_command - from pystencils import Assignment, Field, show_code + from pystencils import Assignment, Field, Target import numpy as np import sympy as sp except ModuleNotFoundError: @@ -56,8 +56,7 @@ def test_jacobi_fixed_field_size_gpu(): dst_field_llvm = to_gpu(dst_field_llvm) jacobi = Assignment(d[0, 0], (f[1, 0] + f[-1, 0] + f[0, 1] + f[0, -1]) / 4) - ast = create_kernel([jacobi], target='gpu') - show_code(ast) + ast = create_kernel([jacobi], target=Target.GPU) for x in range(1, size[0] - 1): for y in range(1, size[1] - 1): diff --git a/pystencils_tests/test_loop_cutting.py b/pystencils_tests/test_loop_cutting.py index 53411715a50ded507dfa748943584ff72b95fe2a..9c833aca66b2143a984eb6d5b29d514c1b2a2da4 100644 --- a/pystencils_tests/test_loop_cutting.py +++ b/pystencils_tests/test_loop_cutting.py @@ -123,9 +123,9 @@ def test_staggered_gpu(): expressions = [(f[0, 0] + f[-1, 0]) / 2, (f[0, 0] + f[0, -1]) / 2] assignments = [ps.Assignment(s.staggered_access(d), expressions[i]) for i, d in enumerate(s.staggered_stencil)] - kernel_ast = ps.create_staggered_kernel(assignments, target='gpu', gpu_exclusive_conditions=True) + kernel_ast = ps.create_staggered_kernel(assignments, target=ps.Target.GPU, gpu_exclusive_conditions=True) assert len(kernel_ast.atoms(Conditional)) == 4 assignments = [ps.Assignment(s.staggered_access(d), expressions[i]) for i, d in enumerate(s.staggered_stencil)] - kernel_ast = ps.create_staggered_kernel(assignments, target='gpu', gpu_exclusive_conditions=False) + kernel_ast = ps.create_staggered_kernel(assignments, target=ps.Target.GPU, gpu_exclusive_conditions=False) assert len(kernel_ast.atoms(Conditional)) == 3 diff --git a/pystencils_tests/test_opencl.py b/pystencils_tests/test_opencl.py index 6c013cefed7387827888385feeb11352b96cc8e6..e5995742e788572405cf60becf5d1e32b5faa674 100644 --- a/pystencils_tests/test_opencl.py +++ b/pystencils_tests/test_opencl.py @@ -25,7 +25,7 @@ def test_print_opencl(): print(assignments) - ast = pystencils.create_kernel(assignments, target='gpu') + ast = pystencils.create_kernel(assignments, target=pystencils.Target.GPU) print(ast) @@ -51,7 +51,7 @@ def test_opencl_jit_fixed_size(): print(assignments) - ast = pystencils.create_kernel(assignments, target='gpu') + ast = pystencils.create_kernel(assignments, target=pystencils.Target.GPU) # TODO maybe Target Opencl print(ast) @@ -105,7 +105,7 @@ def test_opencl_jit(): print(assignments) - ast = pystencils.create_kernel(assignments, target='gpu') + ast = pystencils.create_kernel(assignments, target=pystencils.Target.GPU) print(ast) @@ -159,7 +159,7 @@ def test_opencl_jit_with_parameter(): print(assignments) - ast = pystencils.create_kernel(assignments, target='gpu') + ast = pystencils.create_kernel(assignments, target=pystencils.Target.GPU) print(ast) @@ -211,7 +211,7 @@ def test_without_cuda(): print(assignments) - ast = pystencils.create_kernel(assignments, target='gpu') + ast = pystencils.create_kernel(assignments, target=pystencils.Target.GPU) print(ast) @@ -247,7 +247,7 @@ def test_kernel_creation(): print(assignments) import pystencils.opencl.autoinit - ast = pystencils.create_kernel(assignments, target='opencl') + ast = pystencils.create_kernel(assignments, target=pystencils.Target.OPENCL) print(ast.backend) diff --git a/pystencils_tests/test_phasefield_dentritic_3D.ipynb b/pystencils_tests/test_phasefield_dentritic_3D.ipynb index b9e73677ecb083015a42b21997577495fd95f73a..a9a51773e9e1dbbd487bea43b8d59005773c8f1b 100644 --- a/pystencils_tests/test_phasefield_dentritic_3D.ipynb +++ b/pystencils_tests/test_phasefield_dentritic_3D.ipynb @@ -36,8 +36,8 @@ "metadata": {}, "outputs": [], "source": [ - "target = 'gpu'\n", - "gpu = target == 'gpu'\n", + "target = ps.Target.GPU\n", + "gpu = target == ps.Target.GPU\n", "domain_size = (25, 25, 25) if 'is_test_run' in globals() else (300, 300, 300)\n", "\n", "dh = ps.create_data_handling(domain_size=domain_size, periodicity=True, default_target=target)\n", @@ -374,4 +374,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/pystencils_tests/test_print_infinity.py b/pystencils_tests/test_print_infinity.py index 9e2dbd29b18389265b206513ec6c4625e0722a10..c4cbb0a88ab4684363ee4ee21e5d38052a448d47 100644 --- a/pystencils_tests/test_print_infinity.py +++ b/pystencils_tests/test_print_infinity.py @@ -6,7 +6,7 @@ from sympy import oo @pytest.mark.parametrize('type', ('float32', 'float64', 'int64')) @pytest.mark.parametrize('negative', (False, 'Negative')) -@pytest.mark.parametrize('target', ('cpu', 'gpu')) +@pytest.mark.parametrize('target', (pystencils.Target.CPU, pystencils.Target.GPU)) def test_print_infinity(type, negative, target): x = pystencils.fields(f'x: {type}[1d]') @@ -17,7 +17,7 @@ def test_print_infinity(type, negative, target): assignment = pystencils.Assignment(x.center, oo) ast = pystencils.create_kernel(assignment, data_type=type, target=target) - if target == 'gpu': + if target == pystencils.Target.GPU: pytest.importorskip('pycuda') ast.compile() diff --git a/pystencils_tests/test_random.py b/pystencils_tests/test_random.py index aa6325961d0c8cfb6dbee893f43a443368501994..5e53ce1391fd130fd1f898f55c23bd1c118d4c1d 100644 --- a/pystencils_tests/test_random.py +++ b/pystencils_tests/test_random.py @@ -7,6 +7,7 @@ from pystencils.rng import PhiloxFourFloats, PhiloxTwoDoubles, AESNIFourFloats, from pystencils.backends.simd_instruction_sets import get_supported_instruction_sets from pystencils.cpu.cpujit import get_compiler_config from pystencils.data_types import TypedSymbol +from pystencils.enums import Target RNGs = {('philox', 'float'): PhiloxFourFloats, ('philox', 'double'): PhiloxTwoDoubles, ('aesni', 'float'): AESNIFourFloats, ('aesni', 'double'): AESNITwoDoubles} @@ -21,17 +22,18 @@ if get_compiler_config()['os'] == 'windows': instruction_sets.remove('avx512') -@pytest.mark.parametrize('target,rng', (('cpu', 'philox'), ('cpu', 'aesni'), ('gpu', 'philox'), ('opencl', 'philox'))) +@pytest.mark.parametrize('target,rng', ( +(Target.CPU, 'philox'), (Target.CPU, 'aesni'), (Target.GPU, 'philox'), (Target.OPENCL, 'philox'))) @pytest.mark.parametrize('precision', ('float', 'double')) @pytest.mark.parametrize('dtype', ('float', 'double')) def test_rng(target, rng, precision, dtype, t=124, offsets=(0, 0), keys=(0, 0), offset_values=None): - if target == 'gpu': + if target == Target.GPU: pytest.importorskip('pycuda') - if target == 'opencl': + if target == Target.OPENCL: pytest.importorskip('pyopencl') from pystencils.opencl.opencljit import init_globally init_globally() - if instruction_sets and set(['neon', 'sve', 'vsx', 'rvv']).intersection(instruction_sets) and rng == 'aesni': + if instruction_sets and {'neon', 'sve', 'vsx', 'rvv'}.intersection(instruction_sets) and rng == 'aesni': pytest.xfail('AES not yet implemented for this architecture') if rng == 'aesni' and len(keys) == 2: keys *= 2 @@ -109,11 +111,11 @@ def test_rng_offsets(kind, vectorized): else: test = test_rng if kind == 'value': - test(instruction_sets[-1] if vectorized else 'cpu', 'philox', 'float', 'float', t=8, + test(instruction_sets[-1] if vectorized else Target.CPU, 'philox', 'float', 'float', t=8, offsets=(6, 7), keys=(5, 309)) elif kind == 'symbol': offsets = (TypedSymbol("x0", np.uint32), TypedSymbol("y0", np.uint32)) - test(instruction_sets[-1] if vectorized else 'cpu', 'philox', 'float', 'float', t=8, + test(instruction_sets[-1] if vectorized else Target.GPU, 'philox', 'float', 'float', t=8, offsets=offsets, offset_values=(6, 7), keys=(5, 309)) @@ -125,7 +127,7 @@ def test_rng_vectorized(target, rng, precision, dtype, t=130, offsets=(1, 3), ke pytest.xfail('AES not yet implemented for this architecture') cpu_vectorize_info = {'assume_inner_stride_one': True, 'assume_aligned': True, 'instruction_set': target} - dh = ps.create_data_handling((131, 131), default_ghost_layers=0, default_target='cpu') + dh = ps.create_data_handling((131, 131), default_ghost_layers=0, default_target=Target.CPU) f = dh.add_array("f", values_per_cell=4 if precision == 'float' else 2, dtype=np.float32 if dtype == 'float' else np.float64, alignment=True) dh.fill(f.name, 42.0) @@ -163,8 +165,8 @@ def test_rng_symbol(vectorized): 'instruction_set': instruction_sets[-1]} else: cpu_vectorize_info = None - - dh = ps.create_data_handling((8, 8), default_ghost_layers=0, default_target="cpu") + + dh = ps.create_data_handling((8, 8), default_ghost_layers=0, default_target=Target.CPU) f = dh.add_array("f", values_per_cell=2 * dh.dim, alignment=True) ac = ps.AssignmentCollection([ps.Assignment(f(i), 0) for i in range(f.shape[-1])]) rng_symbol_gen = random_symbol(ac.subexpressions, dim=dh.dim) @@ -179,7 +181,7 @@ def test_rng_symbol(vectorized): def test_staggered(vectorized): """Make sure that the RNG counter can be substituted during loop cutting""" - dh = ps.create_data_handling((8, 8), default_ghost_layers=0, default_target="cpu") + dh = ps.create_data_handling((8, 8), default_ghost_layers=0, default_target=Target.CPU) j = dh.add_array("j", values_per_cell=dh.dim, field_type=ps.FieldType.STAGGERED_FLUX) a = ps.AssignmentCollection([ps.Assignment(j.staggered_access(n), 0) for n in j.staggered_stencil]) rng_symbol_gen = random_symbol(a.subexpressions, dim=dh.dim, rng_node=PhiloxTwoDoubles) @@ -193,15 +195,15 @@ def test_staggered(vectorized): pytest.importorskip('islpy') cpu_vectorize_info = {'assume_inner_stride_one': True, 'assume_aligned': False, 'instruction_set': instruction_sets[-1]} - + dh.fill(j.name, 867) dh.run_kernel(kernel, seed=5, time_step=309) ref_data = dh.gather_array(j.name) - + kernel2 = ps.create_staggered_kernel(a, target=dh.default_target, cpu_vectorize_info=cpu_vectorize_info).compile() dh.fill(j.name, 867) dh.run_kernel(kernel2, seed=5, time_step=309) data = dh.gather_array(j.name) - + assert np.allclose(ref_data, data) diff --git a/pystencils_tests/test_simplification_strategy.py b/pystencils_tests/test_simplification_strategy.py index 19ade3ddc8b67a2586f4090167968ed581a5560c..31fa435449f5738e0d16639bacf806dd419e0d47 100644 --- a/pystencils_tests/test_simplification_strategy.py +++ b/pystencils_tests/test_simplification_strategy.py @@ -73,7 +73,7 @@ def test_split_inner_loop(): code = ps.get_code_str(ast) # we have four inner loops as indicated in split groups (4 elements) plus one outer loop assert code.count('for') == 5 - ast = ps.create_kernel(ac, target='gpu') + ast = ps.create_kernel(ac, target=ps.Target.GPU) code = ps.get_code_str(ast) # on GPUs is wouldn't be good to use loop splitting diff --git a/pystencils_tests/test_source_code_comment.py b/pystencils_tests/test_source_code_comment.py index 16e6e5a9647843db4483b951aa631b591240dac5..79c25ae797be49b93409d2d810efb01a9eb02233 100644 --- a/pystencils_tests/test_source_code_comment.py +++ b/pystencils_tests/test_source_code_comment.py @@ -19,7 +19,8 @@ def test_source_code_comment(): {a.center(): b[0, 2] + b[0, 0]}, {} ) - ast = pystencils.create_kernel(assignments, target='cpu') + config = pystencils.CreateKernelConfig(target=pystencils.Target.CPU) + ast = pystencils.create_kernel(assignments, config=config) ast.body.append(pystencils.astnodes.SourceCodeComment("Hallo")) ast.body.append(pystencils.astnodes.EmptyLine()) diff --git a/pystencils_tests/test_staggered_kernel.py b/pystencils_tests/test_staggered_kernel.py index eecbf706c5538ad544d29a6b37366944aa504680..1ad634da299e6eb0ac016c27946edf84ab5b016c 100644 --- a/pystencils_tests/test_staggered_kernel.py +++ b/pystencils_tests/test_staggered_kernel.py @@ -5,10 +5,11 @@ import pytest import pystencils as ps from pystencils import x_staggered_vector, TypedSymbol +from pystencils.enums import Target class TestStaggeredDiffusion: - def _run(self, num_neighbors, target='cpu', openmp=False): + def _run(self, num_neighbors, target=ps.Target.CPU, openmp=False): L = (40, 40) D = 0.066 dt = 1 @@ -75,14 +76,14 @@ class TestStaggeredDiffusion: import pytest pytest.importorskip('pyopencl') import pystencils.opencl.autoinit - self._run(4, 'opencl') + self._run(4, Target.OPENCL) def test_diffusion_openmp(self): self._run(4, openmp=True) def test_staggered_subexpressions(): - dh = ps.create_data_handling((10, 10), periodicity=True, default_target='cpu') + dh = ps.create_data_handling((10, 10), periodicity=True, default_target=Target.CPU) j = dh.add_array('j', values_per_cell=2, field_type=ps.FieldType.STAGGERED) c = sp.symbols("c") assignments = [ps.Assignment(j.staggered_access("W"), c), @@ -92,7 +93,7 @@ def test_staggered_subexpressions(): def test_staggered_loop_cutting(): pytest.importorskip('islpy') - dh = ps.create_data_handling((4, 4), periodicity=True, default_target='cpu') + dh = ps.create_data_handling((4, 4), periodicity=True, default_target=Target.CPU) j = dh.add_array('j', values_per_cell=4, field_type=ps.FieldType.STAGGERED) assignments = [ps.Assignment(j.staggered_access("SW"), 1)] ast = ps.create_staggered_kernel(assignments, target=dh.default_target) diff --git a/pystencils_tests/test_sympy_optimizations.py b/pystencils_tests/test_sympy_optimizations.py index 8262cfc1cb95c33beeb5ebe4745442cf89c09cc1..e9e958e511a9fc132388fd99fe4a805b748f8f0e 100644 --- a/pystencils_tests/test_sympy_optimizations.py +++ b/pystencils_tests/test_sympy_optimizations.py @@ -1,21 +1,21 @@ import pytest import sympy as sp -import pystencils +import pystencils as ps from pystencils.math_optimizations import HAS_REWRITING, optimize_assignments, optims_pystencils_cpu, optimize_ast @pytest.mark.skipif(not HAS_REWRITING, reason="need sympy.codegen.rewriting") def test_sympy_optimizations(): - for target in ('cpu', 'gpu'): + for target in (ps.Target.CPU, ps.Target.GPU): for op_ast in (True, False): - x, y, z = pystencils.fields('x, y, z: float32[2d]') + x, y, z = ps.fields('x, y, z: float32[2d]') # Triggers Sympy's expm1 optimization # Sympy's expm1 optimization is tedious to use and the behaviour is highly depended on the sympy version. In # some cases the exp expression has to be encapsulated in brackets or multiplied with 1 or 1.0 # for sympy to work properly ... - assignments = pystencils.AssignmentCollection({ + assignments = ps.AssignmentCollection({ x[0, 0]: 1.0 * (sp.exp(y[0, 0]) - 1) }) @@ -23,44 +23,44 @@ def test_sympy_optimizations(): assignments = optimize_assignments(assignments, optims_pystencils_cpu) print(assignments) - ast = pystencils.create_kernel(assignments, target=target) + ast = ps.create_kernel(assignments, config=ps.CreateKernelConfig(target=target)) if op_ast: optimize_ast(ast, optims_pystencils_cpu) - code = pystencils.get_code_str(ast) + code = ps.get_code_str(ast) assert 'expm1(' in code @pytest.mark.skipif(not HAS_REWRITING, reason="need sympy.codegen.rewriting") def test_evaluate_constant_terms(): - for target in ('cpu', 'gpu'): - x, y, z = pystencils.fields('x, y, z: float32[2d]') + for target in (ps.Target.CPU, ps.Target.GPU): + x, y, z = ps.fields('x, y, z: float32[2d]') # Triggers Sympy's cos optimization - assignments = pystencils.AssignmentCollection({ + assignments = ps.AssignmentCollection({ x[0, 0]: -sp.cos(1) + y[0, 0] }) assignments = optimize_assignments(assignments, optims_pystencils_cpu) - ast = pystencils.create_kernel(assignments, target=target) - code = pystencils.get_code_str(ast) + ast = ps.create_kernel(assignments, config=ps.CreateKernelConfig(target=target)) + code = ps.get_code_str(ast) assert 'cos(' not in code print(code) @pytest.mark.skipif(not HAS_REWRITING, reason="need sympy.codegen.rewriting") def test_do_not_evaluate_constant_terms(): - optimizations = pystencils.math_optimizations.optims_pystencils_cpu - optimizations.remove(pystencils.math_optimizations.evaluate_constant_terms) + optimizations = ps.math_optimizations.optims_pystencils_cpu + optimizations.remove(ps.math_optimizations.evaluate_constant_terms) - for target in ('cpu', 'gpu'): - x, y, z = pystencils.fields('x, y, z: float32[2d]') + for target in (ps.Target.CPU, ps.Target.GPU): + x, y, z = ps.fields('x, y, z: float32[2d]') - assignments = pystencils.AssignmentCollection({ + assignments = ps.AssignmentCollection({ x[0, 0]: -sp.cos(1) + y[0, 0] }) - ast = pystencils.create_kernel(assignments, target=target) - code = pystencils.get_code_str(ast) + ast = ps.create_kernel(assignments, config=ps.CreateKernelConfig(target=target)) + code = ps.get_code_str(ast) assert 'cos(' in code print(code) diff --git a/pystencils_tests/test_vectorization.py b/pystencils_tests/test_vectorization.py index 00618a061693db943e7feac058766e5434f1b33d..9c34949be7df30aba86186a5ac5abd516c03f117 100644 --- a/pystencils_tests/test_vectorization.py +++ b/pystencils_tests/test_vectorization.py @@ -5,6 +5,7 @@ import pystencils as ps from pystencils.backends.simd_instruction_sets import get_supported_instruction_sets from pystencils.cpu.vectorization import vectorize from pystencils.fast_approximation import insert_fast_sqrts, insert_fast_divisions +from pystencils.enums import Target from pystencils.transformations import replace_inner_stride_with_one supported_instruction_sets = get_supported_instruction_sets() @@ -36,7 +37,7 @@ def test_vector_type_propagation(instruction_set=instruction_set): def test_aligned_and_nt_stores(instruction_set=instruction_set, openmp=False): domain_size = (24, 24) # create a datahandling object - dh = ps.create_data_handling(domain_size, periodicity=(True, True), parallel=False, default_target='cpu') + dh = ps.create_data_handling(domain_size, periodicity=(True, True), parallel=False, default_target=Target.CPU) # fields alignment = 'cacheline' if openmp else True @@ -47,7 +48,8 @@ def test_aligned_and_nt_stores(instruction_set=instruction_set, openmp=False): opt = {'instruction_set': instruction_set, 'assume_aligned': True, 'nontemporal': True, 'assume_inner_stride_one': True} update_rule = [ps.Assignment(f.center(), 0.25 * (g[-1, 0] + g[1, 0] + g[0, -1] + g[0, 1]))] - ast = ps.create_kernel(update_rule, target=dh.default_target, cpu_vectorize_info=opt, cpu_openmp=openmp) + config = ps.CreateKernelConfig(target=dh.default_target, cpu_vectorize_info=opt, cpu_openmp=openmp) + ast = ps.create_kernel(update_rule, config=config) if instruction_set in ['sse'] or instruction_set.startswith('avx'): assert 'stream' in ast.instruction_set assert 'streamFence' in ast.instruction_set @@ -82,7 +84,8 @@ def test_inplace_update(instruction_set=instruction_set): f1 @= 2 * s.tmp0 f2 @= 2 * s.tmp0 - ast = ps.create_kernel(update_rule, cpu_vectorize_info={'instruction_set': instruction_set}) + config = ps.CreateKernelConfig(cpu_vectorize_info={'instruction_set': instruction_set}) + ast = ps.create_kernel(update_rule, config=config) kernel = ast.compile() kernel(f=arr) np.testing.assert_equal(arr, 2) diff --git a/pystencils_tests/test_vectorization_specific.py b/pystencils_tests/test_vectorization_specific.py index 1c0c35e535de82cfb95b6b5743a17fa7b532c185..6c2f144a4273393efa5bca3b84c1aae0a840889e 100644 --- a/pystencils_tests/test_vectorization_specific.py +++ b/pystencils_tests/test_vectorization_specific.py @@ -7,6 +7,7 @@ import pystencils as ps from pystencils.backends.simd_instruction_sets import (get_cacheline_size, get_supported_instruction_sets, get_vector_instruction_set) from pystencils.data_types import cast_func, VectorType +from pystencils.enums import Target supported_instruction_sets = get_supported_instruction_sets() if get_supported_instruction_sets() else [] @@ -27,7 +28,8 @@ def test_vectorisation_varying_arch(instruction_set): f1 @= 2 * s.tmp0 f2 @= 2 * s.tmp0 - ast = ps.create_kernel(update_rule, cpu_vectorize_info={'instruction_set': instruction_set}) + config = ps.CreateKernelConfig(cpu_vectorize_info={'instruction_set': instruction_set}) + ast = ps.create_kernel(update_rule, config=config) kernel = ast.compile() kernel(f=arr) np.testing.assert_equal(arr, 2) @@ -45,7 +47,8 @@ def test_vectorized_abs(instruction_set, dtype): f, g = ps.fields(f=arr, g=arr) update_rule = [ps.Assignment(g.center(), sp.Abs(f.center()))] - ast = ps.create_kernel(update_rule, cpu_vectorize_info={'instruction_set': instruction_set}) + config = ps.CreateKernelConfig(cpu_vectorize_info={'instruction_set': instruction_set}) + ast = ps.create_kernel(update_rule, config=config) func = ast.compile() dst = np.zeros_like(arr) @@ -60,11 +63,13 @@ def test_strided(instruction_set, dtype): update_rule = [ps.Assignment(g[0, 0], f[0, 0] + f[-1, 0] + f[1, 0] + f[0, 1] + f[0, -1] + 42.0)] if 'storeS' not in get_vector_instruction_set(dtype, instruction_set) and not instruction_set in ['avx512', 'rvv'] and not instruction_set.startswith('sve'): with pytest.warns(UserWarning) as warn: - ast = ps.create_kernel(update_rule, cpu_vectorize_info={'instruction_set': instruction_set}) + config = ps.CreateKernelConfig(cpu_vectorize_info={'instruction_set': instruction_set}) + ast = ps.create_kernel(update_rule, config=config) assert 'Could not vectorize loop' in warn[0].message.args[0] else: with pytest.warns(None) as warn: - ast = ps.create_kernel(update_rule, cpu_vectorize_info={'instruction_set': instruction_set}) + config = ps.CreateKernelConfig(cpu_vectorize_info={'instruction_set': instruction_set}) + ast = ps.create_kernel(update_rule, config=config) assert len(warn) == 0 func = ast.compile() ref_func = ps.create_kernel(update_rule).compile() @@ -85,7 +90,7 @@ def test_alignment_and_correct_ghost_layers(gl_field, gl_kernel, instruction_set dtype = np.float64 if dtype == 'double' else np.float32 domain_size = (128, 128) - dh = ps.create_data_handling(domain_size, periodicity=(True, True), default_target='cpu') + dh = ps.create_data_handling(domain_size, periodicity=(True, True), default_target=Target.CPU) src = dh.add_array("src", values_per_cell=1, dtype=dtype, ghost_layers=gl_field, alignment=True) dh.fill(src.name, 1.0, ghost_layers=True) dst = dh.add_array("dst", values_per_cell=1, dtype=dtype, ghost_layers=gl_field, alignment=True) @@ -94,7 +99,8 @@ def test_alignment_and_correct_ghost_layers(gl_field, gl_kernel, instruction_set update_rule = ps.Assignment(dst[0, 0], src[0, 0]) opt = {'instruction_set': instruction_set, 'assume_aligned': True, 'nontemporal': True, 'assume_inner_stride_one': True} - ast = ps.create_kernel(update_rule, target=dh.default_target, cpu_vectorize_info=opt, ghost_layers=gl_kernel) + config = ps.CreateKernelConfig(target=dh.default_target, cpu_vectorize_info=opt, ghost_layers=gl_kernel) + ast = ps.create_kernel(update_rule, config=config) kernel = ast.compile() if gl_kernel != gl_field: with pytest.raises(ValueError): diff --git a/pytest.ini b/pytest.ini index 039d41b593e3ccf0a57deecdf44f7aeaf590d46a..c9f58e6b7c6fa397a93412a5f103e3ada68ca9d4 100644 --- a/pytest.ini +++ b/pytest.ini @@ -22,6 +22,7 @@ omit = doc/* pystencils/cache.py pystencils/pacxx/benchmark.py pystencils/_version.py + venv/ [report] exclude_lines =