From 5a962fb66923899364e71715231c485d514f8e0f Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 4 Nov 2018 23:55:55 -0600 Subject: [PATCH 1/9] Actually implement Evaluator mapper --- grudge/symbolic/mappers/__init__.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/grudge/symbolic/mappers/__init__.py b/grudge/symbolic/mappers/__init__.py index 2b0b2242..73762157 100644 --- a/grudge/symbolic/mappers/__init__.py +++ b/grudge/symbolic/mappers/__init__.py @@ -1263,7 +1263,32 @@ class FluxExchangeCollector(CSECachingMapperMixin, CollectorMixin, CombineMapper # {{{ evaluation class Evaluator(pymbolic.mapper.evaluator.EvaluationMapper): - pass + def map_operator_binding(self, expr): + return expr.op(self.rec(expr.field)) + + def map_node_coordinate_component(self, expr): + return expr + + def map_call(self, expr): + return type(expr)( + expr.function, + tuple(self.rec(child, *args, **kwargs) + for child in expr.parameters)) + + def map_call_with_kwargs(self, expr): + return type(expr)( + expr.function, + tuple(self.rec(child, *args, **kwargs) + for child in expr.parameters), + dict( + (key, self.rec(val, *args, **kwargs)) + for key, val in six.iteritems(expr.kw_parameters)) + ) + + def map_common_subexpression(self, expr): + return type(expr)(expr.child, expr.prefix, expr.scope) + + # }}} -- GitLab From 22732e9a0c169de0efea0b67abfff973a2f1af89 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 4 Nov 2018 23:59:38 -0600 Subject: [PATCH 2/9] Implement initial dagrt->grudge rewriter --- examples/dagrt-fusion.py | 141 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 examples/dagrt-fusion.py diff --git a/examples/dagrt-fusion.py b/examples/dagrt-fusion.py new file mode 100644 index 00000000..2ddf1332 --- /dev/null +++ b/examples/dagrt-fusion.py @@ -0,0 +1,141 @@ +from grudge.models.wave import StrongWaveOperator +from leap.rk import LSRK4Method +from dagrt.codegen import PythonCodeGenerator +import numpy as np + +dt_method = LSRK4Method(component_id="w") +dt_code = dt_method.generate() +from grudge import sym + +import dagrt.language as lang +import pymbolic.mapper as pmap +import pymbolic.primitives as p +import grudge.symbolic.mappers as gmap + + +def topological_sort(stmts, root_deps): + id_to_stmt = {stmt.id: stmt for stmt in stmts} + + ordered_stmts = [] + satisfied = set() + + def satisfy_dep(name): + if name in satisfied: + return + + stmt = id_to_stmt[name] + for dep in stmt.depends_on: + satisfy_dep(dep) + ordered_stmts.append(stmt) + satisfied.add(name) + + for d in root_deps: + satisfy_dep(d) + + return ordered_stmts + + +class DagrtToGrudgeRewriter(pmap.IdentityMapper): + def __init__(self, context): + self.context = context + + def map_variable(self, expr): + return self.context[expr.name] + + def map_call(self, expr): + raise ValueError("function call not expected") + + +class GrudgeArgSubstitutor(gmap.IdentityMapper): + def __init__(self, args): + self.args = args + + def map_variable(self, expr): + if expr.name in self.args: + return self.args[expr.name] + else: + return super().map_variable(expr) + + +def transcribe_phase(dag, phase_name, rhs_name, op_sym_expr): + phase = dag.phases[phase_name] + + ctx = {"": sym.var("t", sym.DD_SCALAR), + "
": sym.var("dt", sym.DD_SCALAR), + "w": sym.make_sym_array("w", 3), + "

residual": sym.var("residual") + } + output_vars = [v for v in ctx.keys()] + yielded_states = [] + + from dagrt.codegen.transform import isolate_function_calls_in_phase + ordered_stmts = topological_sort( + isolate_function_calls_in_phase( + phase, + dag.get_stmt_id_generator(), + dag.get_var_name_generator()).statements, + phase.depends_on) + + for stmt in ordered_stmts: + if stmt.condition is not True: + raise NotImplementedError( + "non-True condition (in statement '%s') not supported" + % stmt.id) + + if isinstance(stmt, lang.Nop): + pass + elif isinstance(stmt, lang.AssignExpression): + if not isinstance(stmt.lhs, p.Variable): + raise NotImplementedError("lhs of statement %s is not a variable: %s" + % (stmt.id, stmt.lhs)) + print(stmt.lhs.name) + ctx[stmt.lhs.name] = sym.cse( + DagrtToGrudgeRewriter(ctx)(stmt.rhs), + stmt.lhs.name) + elif isinstance(stmt, lang.AssignFunctionCall): + if stmt.function_id != rhs_name: + raise NotImplementedError("statement '%s' calls unsupported function '%s'" + % (stmt.id, stmt.function_id)) + if stmt.parameters: + raise NotImplementedError( + "statement '%s' calls function '%s' with positional arguments" + % (stmt.id, stmt.function_id)) + kwargs = {name: sym.cse(DagrtToGrudgeRewriter(ctx)(arg)) + for name, arg in stmt.kw_parameters.items()} + + if len(stmt.assignees) != 1: + raise NotImplementedError( + "statement '%s' calls function '%s' " + "with more than one LHS" + % (stmt.id, stmt.function_id)) + + assignee, = stmt.assignees + ctx[assignee] = GrudgeArgSubstitutor( + kwargs)(op_sym_expr) + elif isinstance(stmt, lang.YieldState): + d2g = DagrtToGrudgeRewriter(ctx) + yielded_states.append( + (stmt.time_id, d2g(stmt.time), stmt.component_id, d2g(stmt.expression))) + else: + raise NotImplementedError("statement %s is of unsupported type ''%s'" + % (stmt.id, type(stmt).__name__)) + + return output_vars, [ctx[ov] for ov in output_vars], yielded_states + + +def main(): + pass + from meshmode.mesh import BTAG_ALL, BTAG_NONE + op = StrongWaveOperator(-0.1, 2, + dirichlet_tag=BTAG_NONE, + neumann_tag=BTAG_NONE, + radiation_tag=BTAG_ALL, + flux_type="upwind") + sym_op = op.sym_operator() + + ov, results, ys = transcribe_phase(dt_code, "primary", "w", sym_op) + for ov_i, res_i in zip(ov, results): + print(ov_i, sym.pretty(res_i)) + +if __name__ == "__main__": + main() -- GitLab From 0eea5b75949d315d7d4d47a511fe1dcdab5a5a0a Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 5 Nov 2018 00:24:25 -0600 Subject: [PATCH 3/9] Un-confuse symbolic and non-symbolic evaluator --- examples/dagrt-fusion.py | 48 ++++++++++++++++++----------- grudge/symbolic/mappers/__init__.py | 4 +++ 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/examples/dagrt-fusion.py b/examples/dagrt-fusion.py index 2ddf1332..2fbcc12f 100644 --- a/examples/dagrt-fusion.py +++ b/examples/dagrt-fusion.py @@ -1,16 +1,16 @@ from grudge.models.wave import StrongWaveOperator from leap.rk import LSRK4Method -from dagrt.codegen import PythonCodeGenerator -import numpy as np +import numpy as np # noqa dt_method = LSRK4Method(component_id="w") dt_code = dt_method.generate() from grudge import sym import dagrt.language as lang -import pymbolic.mapper as pmap import pymbolic.primitives as p import grudge.symbolic.mappers as gmap +from pymbolic.mapper.evaluator import EvaluationMapper \ + as PymbolicEvaluationMapper def topological_sort(stmts, root_deps): @@ -35,7 +35,10 @@ def topological_sort(stmts, root_deps): return ordered_stmts -class DagrtToGrudgeRewriter(pmap.IdentityMapper): +# Use evaluation, not identity mappers to propagate symbolic vectors to +# outermost level. + +class DagrtToGrudgeRewriter(PymbolicEvaluationMapper): def __init__(self, context): self.context = context @@ -46,24 +49,27 @@ class DagrtToGrudgeRewriter(pmap.IdentityMapper): raise ValueError("function call not expected") -class GrudgeArgSubstitutor(gmap.IdentityMapper): +class GrudgeArgSubstitutor(gmap.SymbolicEvaluator): def __init__(self, args): self.args = args - def map_variable(self, expr): + def map_grudge_variable(self, expr): if expr.name in self.args: return self.args[expr.name] else: return super().map_variable(expr) -def transcribe_phase(dag, phase_name, rhs_name, op_sym_expr): +def transcribe_phase(dag, phase_name, rhs_name, sym_operator): + sym_operator = gmap.OperatorBinder()(sym_operator) + phase = dag.phases[phase_name] - ctx = {"": sym.var("t", sym.DD_SCALAR), - "

": sym.var("dt", sym.DD_SCALAR), - "w": sym.make_sym_array("w", 3), - "

residual": sym.var("residual") + ctx = { + "": sym.var("t", sym.DD_SCALAR), + "

": sym.var("dt", sym.DD_SCALAR), + "w": sym.make_sym_array("w", 3), + "

residual_w": sym.var("residual") } output_vars = [v for v in ctx.keys()] yielded_states = [] @@ -88,13 +94,16 @@ def transcribe_phase(dag, phase_name, rhs_name, op_sym_expr): if not isinstance(stmt.lhs, p.Variable): raise NotImplementedError("lhs of statement %s is not a variable: %s" % (stmt.id, stmt.lhs)) - print(stmt.lhs.name) ctx[stmt.lhs.name] = sym.cse( DagrtToGrudgeRewriter(ctx)(stmt.rhs), - stmt.lhs.name) + ( + stmt.lhs.name + .replace("<", "") + .replace(">", ""))) elif isinstance(stmt, lang.AssignFunctionCall): if stmt.function_id != rhs_name: - raise NotImplementedError("statement '%s' calls unsupported function '%s'" + raise NotImplementedError( + "statement '%s' calls unsupported function '%s'" % (stmt.id, stmt.function_id)) if stmt.parameters: raise NotImplementedError( @@ -111,11 +120,12 @@ def transcribe_phase(dag, phase_name, rhs_name, op_sym_expr): assignee, = stmt.assignees ctx[assignee] = GrudgeArgSubstitutor( - kwargs)(op_sym_expr) + kwargs)(sym_operator) elif isinstance(stmt, lang.YieldState): d2g = DagrtToGrudgeRewriter(ctx) yielded_states.append( - (stmt.time_id, d2g(stmt.time), stmt.component_id, d2g(stmt.expression))) + (stmt.time_id, d2g(stmt.time), stmt.component_id, + d2g(stmt.expression))) else: raise NotImplementedError("statement %s is of unsupported type ''%s'" % (stmt.id, type(stmt).__name__)) @@ -124,7 +134,6 @@ def transcribe_phase(dag, phase_name, rhs_name, op_sym_expr): def main(): - pass from meshmode.mesh import BTAG_ALL, BTAG_NONE op = StrongWaveOperator(-0.1, 2, dirichlet_tag=BTAG_NONE, @@ -135,7 +144,10 @@ def main(): ov, results, ys = transcribe_phase(dt_code, "primary", "w", sym_op) for ov_i, res_i in zip(ov, results): - print(ov_i, sym.pretty(res_i)) + print(75*"#") + print(sym.pretty(res_i)) + print(f"{ov_i} IS THE ABOVE ^") + if __name__ == "__main__": main() diff --git a/grudge/symbolic/mappers/__init__.py b/grudge/symbolic/mappers/__init__.py index 73762157..4c9ad5d4 100644 --- a/grudge/symbolic/mappers/__init__.py +++ b/grudge/symbolic/mappers/__init__.py @@ -1263,6 +1263,10 @@ class FluxExchangeCollector(CSECachingMapperMixin, CollectorMixin, CombineMapper # {{{ evaluation class Evaluator(pymbolic.mapper.evaluator.EvaluationMapper): + pass + + +class SymbolicEvaluator(pymbolic.mapper.evaluator.EvaluationMapper): def map_operator_binding(self, expr): return expr.op(self.rec(expr.field)) -- GitLab From 0c0a3197bc46ade2fb88d26e20fe5650821155e6 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 5 Nov 2018 00:34:11 -0600 Subject: [PATCH 4/9] SymbolicEvaluator: placate flake8 --- grudge/symbolic/mappers/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/grudge/symbolic/mappers/__init__.py b/grudge/symbolic/mappers/__init__.py index 4c9ad5d4..ca6d976f 100644 --- a/grudge/symbolic/mappers/__init__.py +++ b/grudge/symbolic/mappers/__init__.py @@ -1267,19 +1267,19 @@ class Evaluator(pymbolic.mapper.evaluator.EvaluationMapper): class SymbolicEvaluator(pymbolic.mapper.evaluator.EvaluationMapper): - def map_operator_binding(self, expr): - return expr.op(self.rec(expr.field)) + def map_operator_binding(self, expr, *args, **kwargs): + return expr.op(self.rec(expr.field, *args, **kwargs)) - def map_node_coordinate_component(self, expr): + def map_node_coordinate_component(self, expr, *args, **kwargs): return expr - def map_call(self, expr): + def map_call(self, expr, *args, **kwargs): return type(expr)( expr.function, tuple(self.rec(child, *args, **kwargs) for child in expr.parameters)) - def map_call_with_kwargs(self, expr): + def map_call_with_kwargs(self, expr, *args, **kwargs): return type(expr)( expr.function, tuple(self.rec(child, *args, **kwargs) @@ -1292,8 +1292,6 @@ class SymbolicEvaluator(pymbolic.mapper.evaluator.EvaluationMapper): def map_common_subexpression(self, expr): return type(expr)(expr.child, expr.prefix, expr.scope) - - # }}} -- GitLab From c7de48709cfbf1e86d9dae2fe8d411d846daf5e3 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 27 Nov 2018 14:03:10 -0600 Subject: [PATCH 5/9] Tweak dagrt fusion example to test successful bind --- examples/dagrt-fusion.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/examples/dagrt-fusion.py b/examples/dagrt-fusion.py index 2fbcc12f..1099be11 100644 --- a/examples/dagrt-fusion.py +++ b/examples/dagrt-fusion.py @@ -1,17 +1,16 @@ +import pyopencl as cl from grudge.models.wave import StrongWaveOperator from leap.rk import LSRK4Method import numpy as np # noqa -dt_method = LSRK4Method(component_id="w") -dt_code = dt_method.generate() -from grudge import sym - import dagrt.language as lang import pymbolic.primitives as p import grudge.symbolic.mappers as gmap from pymbolic.mapper.evaluator import EvaluationMapper \ as PymbolicEvaluationMapper +from grudge import sym, bind, DGDiscretizationWithBoundaries + def topological_sort(stmts, root_deps): id_to_stmt = {stmt.id: stmt for stmt in stmts} @@ -66,10 +65,10 @@ def transcribe_phase(dag, phase_name, rhs_name, sym_operator): phase = dag.phases[phase_name] ctx = { - "": sym.var("t", sym.DD_SCALAR), - "

": sym.var("dt", sym.DD_SCALAR), - "w": sym.make_sym_array("w", 3), - "

residual_w": sym.var("residual") + "": sym.var("input_t", sym.DD_SCALAR), + "

": sym.var("input_dt", sym.DD_SCALAR), + "w": sym.make_sym_array("input_w", 3), + "

residual_w": sym.var("input_residual") } output_vars = [v for v in ctx.keys()] yielded_states = [] @@ -134,6 +133,9 @@ def transcribe_phase(dag, phase_name, rhs_name, sym_operator): def main(): + dt_method = LSRK4Method(component_id="w") + dt_code = dt_method.generate() + from meshmode.mesh import BTAG_ALL, BTAG_NONE op = StrongWaveOperator(-0.1, 2, dirichlet_tag=BTAG_NONE, @@ -148,6 +150,21 @@ def main(): print(sym.pretty(res_i)) print(f"{ov_i} IS THE ABOVE ^") + from meshmode.mesh.generation import generate_regular_rect_mesh + mesh = generate_regular_rect_mesh( + a=(-0.5,)*2, + b=(0.5,)*2, + n=(16,)*2) + + cl_ctx = cl.create_some_context() + discr = DGDiscretizationWithBoundaries(cl_ctx, mesh, order=3) + + from pytools.obj_array import join_fields + results = join_fields(results[0], results[1], *results[2], *results[3]) + bound_op = bind(discr, results) + + print(bound_op.eval_code) + if __name__ == "__main__": main() -- GitLab From 6bd7e7ba5374aa03d2403294932291d94b31e1ae Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 5 Dec 2018 15:49:22 -0600 Subject: [PATCH 6/9] Fix recursion in CSE in EvalMapper --- grudge/symbolic/mappers/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grudge/symbolic/mappers/__init__.py b/grudge/symbolic/mappers/__init__.py index 64d26c38..76864e7d 100644 --- a/grudge/symbolic/mappers/__init__.py +++ b/grudge/symbolic/mappers/__init__.py @@ -1294,7 +1294,7 @@ class SymbolicEvaluator(pymbolic.mapper.evaluator.EvaluationMapper): ) def map_common_subexpression(self, expr): - return type(expr)(expr.child, expr.prefix, expr.scope) + return type(expr)(self.rec(expr.child), expr.prefix, expr.scope) # }}} -- GitLab From a55e373194a506b0ee1679e122431c2612974867 Mon Sep 17 00:00:00 2001 From: Fan Kiat Chan Date: Sat, 8 Dec 2018 17:42:01 -0600 Subject: [PATCH 7/9] Fix Code class in compiler.py to be aware of subscripted variables --- grudge/symbolic/compiler.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/grudge/symbolic/compiler.py b/grudge/symbolic/compiler.py index 53db42f1..84a55eea 100644 --- a/grudge/symbolic/compiler.py +++ b/grudge/symbolic/compiler.py @@ -446,7 +446,7 @@ class Code(object): available_insns = [ (insn, insn.priority) for insn in self.instructions if insn not in done_insns - and all(dep.name in available_names + and all( (dep.aggregate.name if isinstance(dep, Subscript) else dep.name) in available_names for dep in insn.get_dependencies())] if not available_insns: @@ -454,7 +454,8 @@ class Code(object): from pytools import flatten discardable_vars = set(available_names) - set(flatten( - [dep.name for dep in insn.get_dependencies()] + # [dep.name for dep in insn.get_dependencies()] + [dep.aggregate.name if isinstance(dep, Subscript) else dep.name for dep in insn.get_dependencies()] for insn in self.instructions if insn not in done_insns)) @@ -578,6 +579,10 @@ class Code(object): future_sub_timer.stop().submit() break + # print("Reachables:") + # for insn in done_insns: + # input(insn) + if len(done_insns) < len(self.instructions): print("Unreachable instructions:") for insn in set(self.instructions) - done_insns: -- GitLab From 7c12f0cfe9e5fd6cf340614dd6f09876eaf18072 Mon Sep 17 00:00:00 2001 From: Fan Kiat Chan Date: Sat, 8 Dec 2018 22:15:12 -0600 Subject: [PATCH 8/9] Fix linter failures in compiler.py --- grudge/symbolic/compiler.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/grudge/symbolic/compiler.py b/grudge/symbolic/compiler.py index 84a55eea..fc94e5eb 100644 --- a/grudge/symbolic/compiler.py +++ b/grudge/symbolic/compiler.py @@ -446,7 +446,8 @@ class Code(object): available_insns = [ (insn, insn.priority) for insn in self.instructions if insn not in done_insns - and all( (dep.aggregate.name if isinstance(dep, Subscript) else dep.name) in available_names + and all((dep.aggregate.name if isinstance(dep, Subscript) + else dep.name) in available_names for dep in insn.get_dependencies())] if not available_insns: @@ -454,8 +455,8 @@ class Code(object): from pytools import flatten discardable_vars = set(available_names) - set(flatten( - # [dep.name for dep in insn.get_dependencies()] - [dep.aggregate.name if isinstance(dep, Subscript) else dep.name for dep in insn.get_dependencies()] + [dep.aggregate.name if isinstance(dep, Subscript) else dep.name + for dep in insn.get_dependencies()] for insn in self.instructions if insn not in done_insns)) @@ -579,10 +580,6 @@ class Code(object): future_sub_timer.stop().submit() break - # print("Reachables:") - # for insn in done_insns: - # input(insn) - if len(done_insns) < len(self.instructions): print("Unreachable instructions:") for insn in set(self.instructions) - done_insns: -- GitLab From 9b81cb7e7387412f08b7b91c9c1644ea3804ccb1 Mon Sep 17 00:00:00 2001 From: Fan Kiat Chan Date: Tue, 11 Dec 2018 14:53:51 -0600 Subject: [PATCH 9/9] Rename dagrt-fusion.py to dagrt_fusion.py for module import --- examples/{dagrt-fusion.py => dagrt_fusion.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{dagrt-fusion.py => dagrt_fusion.py} (100%) diff --git a/examples/dagrt-fusion.py b/examples/dagrt_fusion.py similarity index 100% rename from examples/dagrt-fusion.py rename to examples/dagrt_fusion.py -- GitLab