From 65d17e6491bb454170fc9dd187132ce378ababe8 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Wed, 12 Oct 2016 09:08:44 +0100 Subject: [PATCH 1/2] Devito2.0: Add draft of re-design description --- devito2.0.ipynb | 307 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 devito2.0.ipynb diff --git a/devito2.0.ipynb b/devito2.0.ipynb new file mode 100644 index 0000000..01e8dd7 --- /dev/null +++ b/devito2.0.ipynb @@ -0,0 +1,307 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Installation\n", + "To use [tikzmagic](https://github.com/robjstan/tikzmagic) simply run: `pip install git+git://github.com/robjstan/tikzmagic.git`" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import tikzmagic" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Devito: (Re-)design of the code generation engine\n", + "\n", + "Following the initial `Propagator` a new more flexible approach is required to extend capabilities beyond the current scope. In particular an alternative to the current template-based code generation approach is sought to provide more flexibility when handling sets of expression and loop objects to facilitate more agile manipulation of the code to generate. The particular restrictions of the current implementation we aim to lift are:\n", + "* Hard-coded outer time loop - Users my need to define their own (adaptive) time stepping, which needs to be facilitated through pure Python in the first instance, and possibly symbolic expressions in later development.\n", + "* Explicit tracking of symbol properties (save, loop limits, padding, orders, etc.) on the Propagator making it extremely complex and hard to extend functionality.\n", + "* Limited insertion of \"customisation expression\", such pre/post loops only before and after the space loops.\n", + "* Explicit parameter definition of loop variables on the Propagator, and timestepping on the Operator. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The below diagram aims to describe the desired abstractions and class structures to enable a detailed discussion before implementing the changes in a _non-agile_ fashion. The core idea is that we need the following three core abstractions to manipulate code programmatically by working on an intermediate represention of Python objects:\n", + "* Kernel: Represents a single unit of compilable code; equivalent to Operator/Propapagator.\n", + "* Expression: An expression/assignment that works on a set of variables.\n", + "* Iteration: A single loop with loop bounds over an iteration space or sub-space" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false, + "scrolled": false + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%tikz -s 0.4\n", + "\n", + "%# Style definitions\n", + "\\tikzstyle{line} = [draw, thick];\n", + "\\tikzstyle{arrow} = [-stealth, line];\n", + "\\tikzstyle{box} = [draw, thick, rectangle, rounded corners, font=\\sffamily];\n", + "\\tikzstyle{symbolic} = [box, minimum height=5ex, minimum width=16ex, fill=red!30]\n", + "\\tikzstyle{cg-expr} = [box, minimum height=8ex, minimum width=24ex, fill=green!40]\n", + "\\tikzstyle{cg-iter} = [box, minimum height=8ex, minimum width=24ex, fill=blue!30]\n", + "\n", + "%# Core codegen classes\n", + "\\node (expression) [box, minimum height=18ex, minimum width=24ex] {};\n", + "\\node [anchor=north, font=\\sffamily\\bfseries] at (expression.north) {Expression};\n", + "\\node (expr) [cg-expr, anchor=south, align=left] at (expression.south) \n", + " {- SymPy expr traversal \\\\\n", + " - Symbolic properties \\\\\\ \\ (dims, vars, etc.) \\\\\n", + " - Substitution \\\\\n", + " - C code generation};\n", + "\n", + "\\node (iteration) [box, minimum height=18ex, minimum width=24ex, right=4ex] at (expression.east) {};\n", + "\\node [anchor=north, font=\\sffamily\\bfseries] at (iteration.north) {Iteration};\n", + "\\node (iter) [cg-iter, anchor=south, align=left] at (iteration.south) \n", + " {- {\\sffamily\\bfseries Loop instance} \\\\\n", + " - Loop limits \\\\\\ \\ (variable vs. fixed) \\\\\n", + " - Substitution \\\\\n", + " - C code generation};\n", + "\n", + "\\node (kernel) [box, minimum height=18ex, minimum width=52ex, , above=6ex, xshift=2ex] at (expression.north east) {};\n", + "\\node [anchor=north, font=\\sffamily\\bfseries] at (kernel.north) {StencilKernel};\n", + "\\node (expr) [box, minimum height=14ex, minimum width=52ex, anchor=south, align=left] at (kernel.south) \n", + " {- Universal entry-point: convert SymPy expressions \\\\\n", + " - Manage codegen, compilation and execution \\\\\n", + " - Manage cross expression data (eg. temporaries)\\\\\n", + " - Configurable by users (eg. CSE, blocking, etc.)\\\\\n", + " - Composable/mergeable};\n", + "\n", + "%# Symbolic layer\n", + "\\node (equation) [box, minimum height=18ex, minimum width=52ex, above=6ex] at (kernel.north) {};\n", + "\\node [anchor=north, font=\\sffamily\\bfseries] at (equation.north) {sympy.Equation};\n", + "\n", + "\\node (function) [box, minimum height=14ex, minimum width=24ex, anchor=south west] at (equation.south west) {};\n", + "\\node [anchor=north, font=\\sffamily\\bfseries] at (function.north) {SymbolicData};\n", + "\\node (dim) [symbolic, anchor=south, align=left, minimum width=24ex, minimum height=10ex] at (function.south) \n", + " {- {\\sffamily\\bfseries sympy.Function} \\\\\n", + " - Data allocation};\n", + " \n", + "\\node (dimension) [box, minimum height=14ex, minimum width=24ex, anchor=south east] at (equation.south east) {};\n", + "\\node [anchor=north, font=\\sffamily\\bfseries] at (dimension.north) {Dimension};\n", + "\\node (dim) [symbolic, anchor=south, align=left, minimum width=24ex, minimum height=10ex] at (dimension.south) \n", + " {- {\\sffamily\\bfseries Iteration space} \\\\\n", + " - Function index};" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "The above abstractions exist in the current Devito-master as classes - but they are lacking several key functionalities that the Propagator currently provides (OpenMP pragmas, loop blocking, etc.). However, they do not assume the fixed loop structure that the current Propagator enforces, and they will (hopefully) provide a much cleaner interface that requires minimal user input. Ideally, the loop structure is hereby implicitly derived from the Dimension objects in each expression." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For example, using a familiar source/receiver paradigm, we might want to create the following (pseudo-)code:\n", + "```\n", + "for (int t = 0; t < 5; ++t):\n", + " for (int p = 0; p < 3; ++p):\n", + " [t, p]\n", + " for (int x = 0 x < 12; ++x):\n", + " for (int y = 0; y < 14; ++y):\n", + " [t, x, y]\n", + " for (int p = 0; p < 3; ++p):\n", + " [t, p]\n", + "```\n", + "\n", + "To generate this, all the information we require can be encapsulated in three SymPy expressions:\n", + "```\n", + "eq_src = Eq(u[t, p_x, p_y], u[t, p_x, p_y] + (src[t, p]))\n", + "eq_stencil = Eq(u[t, x, y], (u[t, x, y], m[x, y]))\n", + "eq_rec = Eq(rec[t, p], (u[t, p_x, p_y)))\n", + "```\n", + "Here, the terms ``, `` and `stencil` are short-hand to denote some expanded SymPy expression that depends on `src[t, p]` or `u[t, x, y]` and `p_x`/`p_y` is shorthand for the derived x, y coordinates of the sparse points (which only depend on `p`, not actually on the `x`/`y` loops). From these we should, conceptually, be able to build the entire kernel with:\n", + "```\n", + "kernel = StencilKernel([eq_src, eq_stencil, eq_rec])\n", + "```\n", + "Provided that the order of the equation objects defines the data dependencies between them (ie. first insert the source term into `u`, then update `u` via the stencil and finally extract result from `u`) and assuming that the order of the dimension symbols within the function objects `u`, `m`, `src` and `rec` defines the order of the loop structure, the above **four lines should be sufficient to generate the desired loop nest**. Please also note that no additional parameters need to be passed or set on the kernel object, other than compilation-specific settings." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One of the key criteria for the Expression/Iteration classes is that they compose to yield a \"tree\", in which each component is able to generate it's corresponding C code and to perform recursive symbol and expression substitution. This way, manipulating the internal loop and expression becomes programmable, allowing us to automate various kernel re-writing techniques. As an example, the loop nest defined above would look like the following diagram:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%tikz -s 0.4\n", + "\n", + "%# Style definitions\n", + "\\tikzstyle{line} = [draw, very thick];\n", + "\\tikzstyle{arrow} = [-stealth, line];\n", + "\\tikzstyle{box} = [draw, thick, rectangle, rounded corners, minimum height=4ex, minimum width=24ex, font=\\sffamily];\n", + "\\tikzstyle{expr} = [box, fill=green!40]\n", + "\\tikzstyle{iter} = [box, fill=blue!30]\n", + "\n", + "\\node (kernel) [box] {StencilKernel};\n", + "\\node (t-loop) [iter, below=2ex, xshift=6ex] at (kernel.south) {\\sf Loop over t};\n", + "\\node (p1-loop) [iter, below=2ex, xshift=6ex] at (t-loop.south) {\\sf Loop over p};\n", + "\\node (src-expr) [expr, below=2ex, xshift=6ex] at (p1-loop.south) {\\sf source insertion};\n", + "\\node (x-loop) [iter, below=2ex, xshift=-6ex] at (src-expr.south) {\\sf Loop over x};\n", + "\\node (y-loop) [iter, below=2ex, xshift=6ex] at (x-loop.south) {\\sf Loop over y};\n", + "\\node (stencil) [expr, below=2ex, xshift=6ex] at (y-loop.south) {\\sf stencil};\n", + "\\node (p2-loop) [iter, below=2ex, xshift=-12ex] at (stencil.south) {\\sf Loop over p};\n", + "\\node (rec-expr) [expr, below=2ex, xshift=6ex] at (p2-loop.south) {\\sf receiver interpolation};\n", + "\n", + "\\path [arrow] ([xshift=3ex]kernel.south west) -- +(0,-.62) -- (t-loop.west);\n", + "\\path [arrow] ([xshift=3ex]t-loop.south west) -- +(0,-.62) -- (p1-loop.west);\n", + "\\path [arrow] ([xshift=3ex]p1-loop.south west) -- +(0,-.62) -- (src-expr.west);\n", + "\\path [arrow] ([xshift=3ex]t-loop.south west) -- +(0,-2.49) -- (x-loop.west);\n", + "\\path [arrow] ([xshift=3ex]x-loop.south west) -- +(0,-.62) -- (y-loop.west);\n", + "\\path [arrow] ([xshift=3ex]y-loop.south west) -- +(0,-.62) -- (stencil.west);\n", + "\\path [arrow] ([xshift=3ex]t-loop.south west) -- +(0,-5.3) -- (p2-loop.west);\n", + "\\path [arrow] ([xshift=3ex]p2-loop.south west) -- +(0,-.62) -- (rec-expr.west);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the above tree structure, current functionalities can be implemented as manipulations os Extression/Iteration objects, where for example CSE creates multiple expressions from a single expression, and loop blocking creates additional loops, as shown below:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%tikz -s 0.4\n", + "\n", + "%# Style definitions\n", + "\\tikzstyle{line} = [draw, very thick];\n", + "\\tikzstyle{arrow} = [-stealth, line];\n", + "\\tikzstyle{box} = [draw, thick, rectangle, rounded corners, minimum height=4ex, minimum width=24ex, font=\\sffamily];\n", + "\\tikzstyle{expr} = [box, fill=green!40]\n", + "\\tikzstyle{iter} = [box, fill=blue!30]\n", + "\n", + "\\node (x-loop) [iter, below=2ex, xshift=-6ex] {\\sf Loop over x};\n", + "\\node (y-loop) [iter, below=2ex, xshift=6ex] at (x-loop.south) {\\sf Loop over y};\n", + "\\node (stencil) [expr, below=2ex, xshift=6ex] at (y-loop.south) {\\sf stencil};\n", + "\n", + "\\path [arrow] ([xshift=3ex]x-loop.south west) -- +(0,-.62) -- (y-loop.west);\n", + "\\path [arrow] ([xshift=3ex]y-loop.south west) -- +(0,-.62) -- (stencil.west);\n", + "\n", + "\\node (comment) [below=4ex, xshift=-6ex] at (stencil.south) {Under loop blocking this now becomes:};\n", + "\n", + "\\node (x-outer) [iter, below=24ex] at (x-loop.south) {\\sf Outer x loop};\n", + "\\node (y-outer) [iter, below=2ex, xshift=6ex] at (x-outer.south) {\\sf Outer y loop};\n", + "\\node (x-inner) [iter, below=2ex, xshift=6ex] at (y-outer.south) {\\sf Inner x loop};\n", + "\\node (y-inner) [iter, below=2ex, xshift=6ex] at (x-inner.south) {\\sf Inner y loop};\n", + "\\node (st1) [expr, below=2ex, xshift=6ex] at (y-inner.south) {\\sf stencil};\n", + "\\node (x-rem) [iter, below=2ex, xshift=-24ex] at (st1.south) {\\sf Remainder x loop};\n", + "\\node (y-rem) [iter, below=2ex, xshift=6ex] at (x-rem.south) {\\sf Remainder y loop};\n", + "\\node (st2) [expr, below=2ex, xshift=6ex] at (y-rem.south) {\\sf stencil};\n", + "\n", + "\\path [arrow] ([xshift=3ex]x-outer.south west) -- +(0,-.62) -- (y-outer.west);\n", + "\\path [arrow] ([xshift=3ex]y-outer.south west) -- +(0,-.62) -- (x-inner.west);\n", + "\\path [arrow] ([xshift=3ex]x-inner.south west) -- +(0,-.62) -- (y-inner.west);\n", + "\\path [arrow] ([xshift=3ex]y-inner.south west) -- +(0,-.62) -- (st1.west);\n", + "\\path [arrow] ([xshift=3ex]x-rem.south west) -- +(0,-.62) -- (y-rem.west);\n", + "\\path [arrow] ([xshift=3ex]y-rem.south west) -- +(0,-.62) -- (st2.west);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Final thoughts\n", + "The current re-design only considers \"Propagator\"-level (indexed, tier 2) expressions at the moment. However, the form of the SymPy expression handed down by the user is only relevant to our internal Expression abstraction, so once this class is capable of \"lowering\" \"Operator\"-level (function, tier-1) expression on creation, there is no need to maintain the Operator/Propagator separation. As a results the \"StencilKernel\" abstraction simply becomes the new Operator in Devito 2.0." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From ce2051c81c06f3a95ecdcd25a9f215a2dbda0db9 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Wed, 12 Oct 2016 09:16:13 +0100 Subject: [PATCH 2/2] Devito2.0: Small updates to Iteration abstraction --- devito2.0.ipynb | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/devito2.0.ipynb b/devito2.0.ipynb index 01e8dd7..5686d7b 100644 --- a/devito2.0.ipynb +++ b/devito2.0.ipynb @@ -52,7 +52,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "" ] @@ -70,23 +70,27 @@ "\\tikzstyle{arrow} = [-stealth, line];\n", "\\tikzstyle{box} = [draw, thick, rectangle, rounded corners, font=\\sffamily];\n", "\\tikzstyle{symbolic} = [box, minimum height=5ex, minimum width=16ex, fill=red!30]\n", - "\\tikzstyle{cg-expr} = [box, minimum height=8ex, minimum width=24ex, fill=green!40]\n", - "\\tikzstyle{cg-iter} = [box, minimum height=8ex, minimum width=24ex, fill=blue!30]\n", + "\\tikzstyle{cg-expr} = [box, minimum height=20ex, minimum width=24ex, fill=green!40]\n", + "\\tikzstyle{cg-iter} = [box, minimum height=20ex, minimum width=24ex, fill=blue!30]\n", "\n", "%# Core codegen classes\n", - "\\node (expression) [box, minimum height=18ex, minimum width=24ex] {};\n", + "\\node (expression) [box, minimum height=24ex, minimum width=24ex] {};\n", "\\node [anchor=north, font=\\sffamily\\bfseries] at (expression.north) {Expression};\n", "\\node (expr) [cg-expr, anchor=south, align=left] at (expression.south) \n", " {- SymPy expr traversal \\\\\n", " - Symbolic properties \\\\\\ \\ (dims, vars, etc.) \\\\\n", " - Substitution \\\\\n", - " - C code generation};\n", + " - C code generation \\\\\n", + " \\\\\n", + " };\n", "\n", - "\\node (iteration) [box, minimum height=18ex, minimum width=24ex, right=4ex] at (expression.east) {};\n", + "\\node (iteration) [box, minimum height=24ex, minimum width=24ex, right=4ex] at (expression.east) {};\n", "\\node [anchor=north, font=\\sffamily\\bfseries] at (iteration.north) {Iteration};\n", "\\node (iter) [cg-iter, anchor=south, align=left] at (iteration.south) \n", " {- {\\sffamily\\bfseries Loop instance} \\\\\n", " - Loop limits \\\\\\ \\ (variable vs. fixed) \\\\\n", + " - Vectorisation \\\\\n", + " - OpenMP pragmas \\\\\n", " - Substitution \\\\\n", " - C code generation};\n", "\n", @@ -171,7 +175,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "" ] @@ -228,7 +232,7 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXgAAAIqCAMAAAAZ7aH1AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAVNQTFRF////AAAAAAAAAAAAAAAAAAAAAAAAAAAABAQGBgYIAAAAAwMECwsQCQkMBQUHBQUIAAAADAwREBAXCAgMBgYIAAAACgoOAAAACAgLBAQFAAAAAAAAAAAAJiY2CQkNAwMFCwsQAAAAAAAAAAAAAAAADw8VAAAAAAAABAQGCgoOAAAABQgFBAcEChAKBAYEBwwHAAAAAAAAAAAAAAAAAwUDBQgFCA4IChEKDhcOAAAABwcKAwMECwsQDAwSAAAAAAAABgYILS1BAAAAAAAABQgFBwsHBwwHBAYEAAAAAAAAAAAACgoPAwQDEyATAAAACQ8JAwUDAAAAGBgiMDBEJCQzj4/Ms7P/p6fuVFR3d3eqm5vdX1+Ig4O7a2uZDAwRSEhmPDxVR3dHZqpmmf+ZKUQphd2FHzMfesx6UohScLtwXJlcj+6PChEKPWY9FCIUM1Uz////hbh95wAAAFF0Uk5TACJmqoiZM3fzrxHx/db047vIzcTSRI9Vn+Fpzafs+vLZ3cyX99CP7r/7x6/0/fPWjui/7/Ljj8jNXObP2tfjgvX6t9/Sn8S/58hQ/M/8xPzhsiedUAAAAAFiS0dEAIgFHUgAAAAJcEhZcwAAAHgAAAB4AJ31WmAAABwdSURBVHja7Z37f+LYeYcBC7CJZ4eMV8ummWTWbrbedvaSprubdJo01zZt00teSSAhczVgMGD8///Wc3QXRiAZ4VdHvM/nYyOQOJIeDkdCOvqqUCAIgiAIgsg/xdKJlG3KUgVb0gGonoKiZhsN4KyG7SltzkBttrKObsAPclbpq2BgW41F8/wVtqpUKX6kYiuNSRskbFlpUgUT22hc1NfYstKkrmH7jM0NFLFtpcgPk7XwHcQNQgewZaXJm2QmDSDxJF5oSLxo4puG0Q09muaN4e8h2S83rRc6Ot848JHdjt7t2OP5jzadjyHxicR3e4ah9f3HlqqphtIzw6NvFDZsgm49V8yW2lc0R7zCzA/6VOMTijd7zJ+udN1HLp4P9MOjdWB6jX5L58+7/ZYKXbekbs80kv12I/EMqyq3jIH7yMSr3sv+aKtO99qtNqvwBvOsBn41dBUtSUND4u1H1f7vPjri22ujmfFWm30IhtZhNFtqYG5mb5Bo1iS+ZRnmtVXtu4+OeEMLj261lO6AzaHZsyt3QLyutdVuklmTeAutz7aYYHqPLVXRmZru2mjW3FgHg/hnoHeD4tmgtW0g8THFW3RapgqgtFveIxOvav4RZu9lE6wGRVd7Wu8mIL7PvyDWrg2JT4jZDD2ypqZpbhgd9Tw5JH4j6sGP65N4Ep8l8c2Dn7jNl/iLhDvTiHRydSKkfI7tMzYG5KmHRwna2EJjoisX2LJS5eNesiMmaBggY7tKlQpo2e/PZPVo+gRbVco0TsHIenPTvFHg0zy18Ba1TyH7/KiBrekgyCH+5sdv5YyRpx3JLR8D1LEX4Tgh8UiQeCRIPBIkHgkSjwSJR4LEI0HikSDxSJB4JEg8EiQeiW3iK1XsXINdCHyeKlq8/COAn2Sbn8K7KrbA1MVLoHSzfj2y3taEDZyIEl+FvhAnxoU9PRshXpzYA1E7JESIl4SJPdCVM2yHaYr/WJzYA+MdtsM0xX8mRrANpy1m/9YI8ck6FmPGTYjasTgV8ZgX35N4Er+H+EqJxKOIL0iXpb3EuzET7sBa3ES8vInWMeRNrDc1V2Cpf6Z4L2bCHQjHTezOm+jyMU04CvGXoeN9f/sz4OqfJ96LmfAGQnETMfIm9B4b6h9D0Ie8sb/u1efPEu/lSXgDobiJOHkTPBmh1zkC8ZW6gxM5/Hesxl9LtefVeC9PwhsIxU3EyZswwewm+9UsqPh16lz7c9t4L0/CGwjFTcTJm2j1jcEx5k1IlvZnb1y9PAl3IBw3ESNvotXUEl6olQvxRck5rZBU/FrchDcQjpvYnTfhfBhHJ97j2ReBe/kR9sB63ESMvImked8kfhPJUw/MpO8g8WmIbxpaon3J3IlP63h80rgJ99BBAgQ9Hh/Bx6KccuVbdmxZaSLOOdeWoOdcIxCpl0G+LkcW5XYiN5CrCs8og9bOfJemjgpfCNqTLJrGOwDse0Lt4O/hI2H7Tm5DDnfNffsPb7F7B6/TyF1134SUr3sEiQOJR4LEI0HikSDxSJB4JEg8EiQeCRKPBIlHgsQjQeKRIPFIbBWPHc+6E2x7BxFffI8dRxyD98JG50aKr3751fB2lG1uh199KepJkyjxDRhPsL3GYDIW9bR4hPja13fYTmNy97WYJ6wixEswxTYak6mgu2UR4r8ZYwuNzfgbbIdpiocZts/YzMTs7Rcl/h7bZ2zuSTyJF0T8lG3A53vPKBfiK+4PwRcRP2Zb8PGQxDNqV+ViquIn27zyGk/ibSrXYKlPS/w97JjgiMWXQ8f7fg7A1e8v/n44HE6mM7i/X1hPJrw9n1iP/IswnE1G08lRi1/jH/m/8t7ip8vZ7XA4fwCuer4cDleT0fjucbhasZFz9urD2JJ+tOJL9TC/+Ceryu8tfjh2rLB/iyUrbf4wGjPpE1byYjm3Rh61+HVOrJZm/6ZmAo+zqSP+llX4Ifsk+F7MiJV86zT8JN6nam9b02jjH1Ywt8UP7+4ZU0/8jMSvU3H2JtPZq5ktbfHT5cIW7YifwoLER7C3+HtWwGzFrCwWi9H4gTX0c0/8aPy4GE3mJP4Q4m9XsGLb0MUSlrejxXh5t5z54hdjgOWQxB9CPNu8WkUs7BMqk+mmkamQM/FZP8/tc5sr8d8+YPuMzcO32LLS5P0K22dsVu+xZaVJA/be6L0QQ1H7d0TwXpBzUPeQqwpfKNS+g+EC2+pOFkP4TsxuNVvMfw9wN8w2dwDf5807oyLVf/mrLPPLulTBlkQQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEFkmiLPsCraufpro2Rpc5h9sbQ7gbdYKkVP7I2MsXgx5rV7IbJIUb68tMTXy0/EX21e6WJ194XnRakePbE3snByva0Ma1Lv7Vun3b4Q2aRuL92GezXUI2qbHOOKf7m+ZWJv5Nb6LIXf/oy6780nk2CK38pl3HntXohMEhDPGvxCRbaDlSpyzRLPGsoaG1EpyN4tNCwZtVLVfsEesKaQ/QtF2TrbT21z4am5ED6uuDbTGivEa5cl4AWwt9sjrWn5u52rIoNvswpnBRZrdrm19YVwVsNbDufBK8OudYFpKn4hLyFeLkOjUrtkc63U5VrpUuJf8Frtqiif1EsNr43lLitSrVDl99RwBuTylVSp1L2tmXxVLRZPSo54f+p6sSA1uPg6K53NLzjTRrlWvaqd2AVUqo54ZySftlj2W5zAstqFl64uG6WrulwoX5XWF8JZDWf23uI4ZTSqtcaVN40zkyoc+l4twaZGBvZfYqt2yZ+xGl+8ZrMvlQvydbHmS4VC7ZpXiCvZH7AEF72ltb8V7CkfCEzNyq2fMPG1qvd18GbKR4JcCJbgj+TPrceqN94e4xXeYG1Tox5sNL2FcFbDmb33DqcMJr0AFXdVnZlUDn7zhLD4grUyDWulmfjqNdvNrLJvbHCXgk1VtRpg6cQfsD15O0KyWwIf8CayymXVuF6p+1O5M7XFNwqhEryRfKgIJ1K4wWNjvMIL15WCdFksVAuF9YVwVsOZvf8Ov3SQ3VUNzeQFxDcqgZWR3CWWrvgOfiW8meJ1z3rO/nsDzkqehNfZ/kD8qe1NpXxZspuDsHj2V7lasxYSz6rhFZSC4/myuoUXpHKhKlUL0loRbCGc1XBm778jKN5d1dBMDol0aT8EV8ar8SV70/hEfMn6BpRP/AF7JS/9hoD/v6paA4GJrK0XK61yWXwiviqXqrXgXApSWDzXUbkOzoGN8QpnoxrFylWjEirCWghnNZzZ++8IindXNTSTQ1Lk3/BCLSS+cMW/8VduY199It7aqtXYSG/AWin52tuh4E+L1zW7jXcnKlgVvcpLq9afiC+HvuFWGxUWL/F3h75TvI33Ci9csnGX5WARzkK4q2HP3n9HULw7jTOTxsnBd2sqVyXZ3leQT0Aqlq6Y8NpJQ65eseWsnJRkqcZH+JusMpuqUi7JZf7puAMyVOVG3attsiTJjXLFntibiJXLivvnk2vemtVlPjIw0wbPgPbXt16tFv2RfFqJ7RBVnVbAH+MVXmDtjL3ztLYQBWc17Nn7i+OVwX4gn8jONM5Mqtcv0NBbTdsabFe24g5sxHvdHuDbvvCihp6uTb1xKay6XD3xXqis1zlmbuPhI7fMWs3+27QQxcqGh03lRM0kq+z1E9PC+o4XanXsNREL9mVt7NkosuaNtwmU15MIfnh5761RpVQV6ltOEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEMQTXuTq2hwv3/OoSa8h85zl73Id+TUMbjrZpm2cw8GDBl6Y4qnSaWUffZA38xfnJrbUeAwgV61NA26wjcZEPz/DlpUm5XNsobEx9r6eOUt8McD2GZv2wQOUXpI3RpJ11w1V7T9jm9BNY/vdyVWNTyS+2Ru0O/1eN7EzNdHHS+LX0Ht9/tCFpv+aGev9JH4v8UbP0TgI2iDxBxev9O3HGya7yWt9R2/eQKejsyHD4E1/t6M7zbk1XuejPPFNw7AbKWegaZo3RoINxvGKB8M10GmpKn+h0+0DV97tGYbCHKp9RXPEK8z8oB+o8Xwajb/gDqiaaii9+OZJfEC83dToPWa7y12Ct+Ht9kxDdZ8w8SafRle6/oCq8cd+7NmTeL51DYlvszpscM3cpWde0fSA+BuFDxgDf8Aqwn5G4rcycLT2mayQeEPjhxCb4Y2o2fO3wex1u/qz/96AVUQ71sb5yMV3oG0Z5TU/JL7ZC25EbXStrXrtDnu9DXwate8PWEUYWoLZY8vCEt/q8+bZ1Lirgcr3brh4Xde5xpbeDYlng7wh9z8Qra+zRsr0B1RFZ2+P/2vsiMW3DNBU6PMa2wZVNZh4vQe9dktXe1rvJii+z6uztWvjijdVAIV/ZdwBVVE1SPSFw5aFJ57tmXec/T/Tcao3Q0+34U1jD7CmppnkuM9Ri08TVU02PYkn8WKLb8ZonfIrvh5/dw6bbq5Oukqg76/kZeh/wJaVJkUQ5dxfJ2f9O6QEP2EwMZUPB4/Vf1n+BQYCtDbd849yF/4sAWhGthmcw8d52rI6FKUv3gT5/Ne/eZMtLsoZvmlleshQx16E44TEI0HikSDxSJB4JEg8EiQeCRKPBIlHgsQjQeKRIPFIkHgkSDwSW8SXzt5hpxrs4qIq7JmqSPHFC1D62LkGOzA0+EzUcyZR4os/OBfhMvB2DwQ9Sxgl/gISdkFCQhf1vHiE+JIwsQei9gSJEC9Q7MHgFbbDNMV/iH+dGDY3YnazjBBPsQciiKfYAxzxFHuwv3gvJIZiD15WfK1eSi4+cexBi2IPnjQ1FbgsJRWfJPagyy/ubkJA/LHGHqy38VWw1B8q9kDnm+B+IG/iaGMP5E0H/S5LB4s94E977l7kMccebBR/LX1+qNgDE8yu9zEcc+xBTfbh+zQlrr12uNiDVt8YUOzBUyrXXPsBYw9aTa0XTFih2AOLWl2yD7IeKvbArtRB8RR7YIl3j20fMPZAXX+JYg8CHO4icHPXxfV09f0haBrariOSJP4Q6LuPBB937AGdCEHiLP4vR2wGr7FlpYk4J7ubgp7sjkKUu1royqmY3TuiKJ6et7GlxqCjQANbVcpUXoFmYPfR28GNCh8E7Ui2jeoFdp/UnbyS8tXObEbK2WZMGEg8EiQeCRKPBIlHgsQjQeKRIPFIkHgkSDwSJB4JEo8EiUeCxCOxRXxFqmcdSdRr77eIr32S/ahoDeATUY/dR4mvvQYj++HougGvBTUfJf4M0rhc9fB04AxbYariG0m69qJiCHpiPEK8QH2fFDGrfIT4d+L09uu/w3aYpnhI1P+m85x2KZXMgxa/bALbYariE1kx4l9V5pPKFeAtYTsWk3gSf8zi5XLx2eK7HdMKOXAf3dCDtcwDPdXMg7yIZ09t9c8Qr2oDQ1H8Rzf0wM88sO6HPAhcer9/5kFuxBfqYKl/jniFX4/c8R7d0AM/84DpNQ3vYqhUMg9EFn8ZOt73i58BV/8c8c713+6jG3oQyDxodRUteCHy/pkHIotf41/5v3IK4t3Qg+BG1Oz5uUOpZB6IK74oh/mtVeGf1dSsiXdDDwLida2tppt5IK749c/h2t66piDeDT0IiGeDvCH3nuyfeZAb8VfO/mQa4p3QA198n4+xdm1c8XtnHuRFfMUNjkvnaLy5+7LiPTMP8iLeA+s0SNJL70k8iRdbfNLMg/yJF+Ua8LzFHrxK/pXHQhUz8TwCSZB7K+Qu9qB2mujXIyJazmIPGqCKEDjBfniJ2bsjmurvzo2s92lqG+e/q2KLSp3iGXaoQQzOivuvaAYJH7j8+Y9/LmcMbEEvA3WlR4LEI0HikSDxSJB4JEg8EiQeCRKPBIlHgsQjQeKRIPFIkHgktoivNaSsI/CRzGjx1VP4qZppfg/wTlj1kbEHX4Ca9XNVLb2tCNtSRon/VIxOOHofBD1NKHzsgfqRmCcKI8R/oWQ/XsXGFLSxibokVpQK32ppH2M7TFW8CLcdsTE+w3aYqvhEezSoeRPGG2yHeOJRr74n8ST++eIbJRKPIr5Qvyw9U7wXM7Ejb6KVdt5EPsTXrsFSn1y8FzMRnTfR5a82ISA+jbwJYcXXQ8f73gJw9c8Q78RMbMmb0HtsqB8I+kglb0JY8ZtiD+rPEO9d+x2dN8HTDXpuyWnlTQgqXl47wv38Gr8ufkPehAlm1/sY0sqbEFT8Gnu08eviN+RNtPrGIPW8iXyIf/5ezRPxG/ImWk2tF4y2SSVvIhfi99iPfyr+Sd6EXamD4tPIm8iFeI9D5U2ozahJnp03QeLjfBK7LnF+RuwBid9J09B2FUviD3E8Xt99JPgZeROCHo+PEi/QGagLbFlpckbnXHGQhanyovYyiOIT6leDA+9JlvkT3npX3J5k0VTfwU9/km0AfiRs38ltrB25/MMf/4DdO3gdce+RlgTqSo8EiUeCxCNB4pEg8UiQeCRIPBIkHgkSjwSJR4LEI0HikSDxSGwTX9w/YJXyW5OLl/+EHUccg38TNhk9Mvbge1jNpqNMs7gdwteiZqNHiZdguMAWG4PpHQh63iRCvAxDbKfxWCz/hK0wVfH/vhKhvnNuBb0Rw2bxNVEqPOOrMrbDFMXLkPHtaoDHP2M7TFU8ts74DH+F7VA48VP2tZrfk/gXFz8es7+9Nya5EC/XUhY/2eaV13gSb1G8lGqpir/fVRCJt2nANVe/v/j74XA4GU1ncH+/sJ5NeHs+sR75F2E4Y2MnRy2+HDre9xaY+uLe4qfL2e1wOJo/AFc9Xw6Hq8lofPc4XK3Y2Dl79WFsST9i8Wv8B//3dl/xw7FT8XlBiyXbdZk/jMZM+gTu2fO5NfKoxZfqYf4TeJX/r33FT+DROrZpib9lFX7IPgq+FzNi4m+d0o9a/Bq1S6uRT6GNf1jB3BE/vLtnTD3xMxL/hBNr25rOXs1s6YifLu0jbq74KSxIfJiSvTe5v/h71qrPVlz8YrEYjR9YQz/3xI/Gj4vRZE7in7K3+NsVrPgmdLGE5e1oMV7eLWe++MUYYDkk8QcQzzav9kGYhX2YczLdODYNSDwSORMvygkoJv6X2LZSpAhzbJ+xuTvBtpUm342xfcZlkq+rwCW4xTYak/GX+Yo9+OYrMc66DvNV4QuFyrci9GiajOE9tqm0qb0HeBxmmxV8mbP6blGR6hnnpJSv9p0gCIIgCIIgCIIgCIIgiBxSusC++n8nr8v5O9ZavADN6GSbm8FfTkv7r2qmqP3gXIT89qaWt/OYZ5D8LiUoqL/LVWsjzp0izPMzbFlpIj3nXsw4GKfYstLki+T3ocKiLWoKzEbeRLc0HX572pud98N7eierGLfC3n2DrA3LA9iyXki8Adx8b9c24Om922LcRe45N44/IvH8v67scPS0xpP4NMQ7N1tOAolPRbxV41l7b/KW2eSPXYPf+Fe/sV6z7orqjLAm7OpcvP0GNsK936H1xdA7ekB80zDsOwg7A03TvNmyfTgi8ezHelfTmKtuzzAUkzXnA0NT+obBd/4H/a7RM22HqjYwFH7H9y70DZWJd97QUvuKc4PPptLk7wnUeD6Nxl9wB1RNNZSeSeJBVTXrrtZ6j8nr9luqwm81aNjND6+7muGIt0Z0Wjq/fRyr8e4bWqp/V+xuz/RbLfYmk0+jK11/QNX4Y5/Eg7tpbff4/o3q3yTbNai64p0Rbat1go77BsulZ17Rgvcvv1GsmQz8AasU+9nRi2cq2Vff0PghwmZYfJO1Ir018YYj3n1DaCNq9gbeMHvd/vDYf2/AKqUd+VP6uMRbNpo9u6oGxZu97tMa3wHdGnDfEBSva23Va3fY621rWrXvD1ilGFrU8hyZeJPf25lZaendkHju2GqIguJbvIVmG2X3DUHxbJA35P4HovV1tjE2/QFV0VmxXRLv7MczHbra03o34aZGA1V5Ir7Z62lcvPOGgPg+n8TatXHFmyqAwm8o6g6oCtuYbzmEcSziQ5hPj9p3Nu74daLfEF2oPcA+vuaWwzzHKf4lULf/RibxJD5n4pvbW6d8ia+LcyKkC3k66SqBvr+Sl6Gfq1N/FWFOdjdBzEz2KD6JcfQ8C+jaqbA3m9lI7bUQdb6jCHr3hy3mz+B8YGQcDT6IfGOrCBrlD2+CfP7r37zJFh8uqvlqZzYjQx17EY4TEo8EiUeCxCNB4pEg8UiQeCRIPBIkHgkSjwSJR4LEI0HikSDxSGwRL0sX2IeId/DDsrjX3keKr30KkPVzJoNzuBC1N0KUeH6WUIA+CTfnp4JeEBsl/ox3HBYA8/wVtsJUxYsTe9DeeOvp7BMhvnyOLTQ22sfYDtMU/2Gwv5EXwhCzm2WEeIo9yJ54ij1AE8//U+xBquK9nkQUe/Cy4osnclzxvMZ7IQYJYw/81APni3GEsQdrTU0D6vJO8W7sgRdikDT2wE89aHX56CYExB9J7MF6Gy+BpT5O7IEfYpA09iCQeqDza5f7gbyJY4k9kDdlndblOLEHfohB0tiDYOoBf0/Pbf2PKPZgo3gofx4j9sAPMUgaexBKPQCz630ORxR7UJPD/JZrL8aKPfBDDJLGHoR2XvrGgGIPCsVrsCKVY8UeeCEGSWMPQuKbWi+YsHKksQdXTpJ1rNgDL8QgaexBeHdd9bebRxt7UHHP58S8FnlTiEHi2AN1/SWKPXgRzF0/genq+0PQNLRdRxJI/CHQdx8JPqrYg8/6u3Rkhm6uxJ8p+xt5IQYfsGWlSVWQTgasIfpLvmIPXvUE6FXD0U5F7dK0mQooIgROsB9Z4vbi24z8AQZd7FsT7aDbPz/N2f1zGDXpNfatuHZyepKvdsZzH3omZa7PVj6tPyF74o8EEo8EiUeCxCNB4pEg8UiQeCRIPBIkHgkSjwSJR4LEI0HikdgivliSsk5J3EOZ0eIlgOU42yxB3O9rlPjaf8PjdJR1pmP4s6Bh0VHiv4cZttVYzOB7bIWpipdhiK00JkMQM5c+Qnz5fxbYRmOy+ErMLjgR4r99wBYam4dvsR2mKR5usX3G5lbMbpZR4u+xfcbmnsQnZcr2V+d7z4jEJ2Y8Zn977z3lQrws1dIVP9nmldd4Eu88vbbVpyX+HnZMQOIdrsBSv7/4++FwOJnO4P5+YT2Z8PZ8Yj3yL8JwNhlNJ0ct/rIe5H9/Blz93uKny9ntcDh/AK56vhwOV5PR+O5xuFqxkXP26sPYkn7E4tf4I/93srf44dixwv4tlqy0+cNozKRPWMmL5dwaedTi5bUj3G+tnI/9m5oJPM6mjvhbVuGH7JPgezEjVvKt0/Aftfg1atd2qFAKbfzDCua2+OHdPWPqiZ+R+CfU7SyndPZqZktb/HRpH3FzxU9hQeLDyO4h1r3F37MCZitmZbFYjMYPrKGfe+JH48fFaDIn8RvYW/ztClZsG7pYwvJ2tBgv75YzX/xiDLAckvhDiGebV6uIhX3+cDLdNDIVSDwSORM/x/YZm3muxH/3iO0zNo/fYctKE+n/JthCYzIRt2vNJopfjrGNxmT8pbi9yTZRhQcR+hksHiBvl99LsJplvbmZzFb5amgs5L9ihxrE4K9i9mbaQbEhZ5tGvpp3giAIgiCIw/H/quxAjMdWGnIAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMTAtMTJUMDk6MTU6MjErMDE6MDCRNaXpAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE2LTEwLTEyVDA5OjE1OjIxKzAxOjAw4GgdVQAAABR0RVh0cGRmOlZlcnNpb24AUERGLTEuNSAFXAs5AAAAAElFTkSuQmCC", "text/plain": [ "" ] @@ -279,8 +283,17 @@ "metadata": {}, "source": [ "### Final thoughts\n", - "The current re-design only considers \"Propagator\"-level (indexed, tier 2) expressions at the moment. However, the form of the SymPy expression handed down by the user is only relevant to our internal Expression abstraction, so once this class is capable of \"lowering\" \"Operator\"-level (function, tier-1) expression on creation, there is no need to maintain the Operator/Propagator separation. As a results the \"StencilKernel\" abstraction simply becomes the new Operator in Devito 2.0." + "The current re-design only considers \"Propagator\"-level (indexed, tier 2) expressions at the moment. However, the form of the SymPy expression handed down by the user is only relevant to our internal Expression abstraction, so once this class is capable of \"lowering\" \"Operator\"-level (function, tier-1) expression on creation, there is no need to maintain the Operator/Propagator separation. As a results the \"StencilKernel\" abstraction simply becomes the new Operator in Devito 2.0, which is capable of generically handling expressions in both formats." ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": {