Пример #1
0
    def make_linear_combiner(self, result_dtype, scalar_dtype, sample_vec, arg_count):
        """
        :param result_dtype: dtype of the desired result.
        :param scalar_dtype: dtype of the scalars.
        :param sample_vec: must match states and right hand sides in shape, object
          array composition, and dtypes.
        :returns: a function that accepts `arg_count` arguments
          *((factor0, vec0), (factor1, vec1), ...)* and returns
          `factor0*vec0 + factor1*vec1`.
        """
        from hedge.tools import is_obj_array
        sample_is_obj_array = is_obj_array(sample_vec)

        if sample_is_obj_array:
            sample_vec = sample_vec[0]

        if isinstance(sample_vec, numpy.ndarray) and sample_vec.dtype != object:
            kernel = NumpyLinearCombiner(result_dtype, scalar_dtype, sample_vec,
                    arg_count)
        else:
            kernel = self.make_special_linear_combiner(
                    result_dtype, scalar_dtype, sample_vec, arg_count)

            if kernel is None:
                from warnings import warn
                warn("using unoptimized linear combination routine" + 
                        _NO_VPF_SUGGESTION)
                kernel = UnoptimizedLinearCombiner(result_dtype, scalar_dtype)

        if sample_is_obj_array:
            kernel = ObjectArrayLinearCombinationWrapper(kernel)

        return kernel
Пример #2
0
    def make_linear_combiner(self, result_dtype, scalar_dtype,
            sample_vec, arg_count):
        """
        :param result_dtype: dtype of the desired result.
        :param scalar_dtype: dtype of the scalars.
        :param sample_vec: must match states and right hand sides in shape, object
          array composition, and dtypes.
        :returns: a function that accepts `arg_count` arguments
          *((factor0, vec0), (factor1, vec1), ...)* and returns
          `factor0*vec0 + factor1*vec1`.
        """
        from hedge.tools import is_obj_array
        sample_is_obj_array = is_obj_array(sample_vec)

        if sample_is_obj_array:
            sample_vec = sample_vec[0]

        if isinstance(sample_vec, numpy.ndarray) and sample_vec.dtype != object:
            kernel = NumpyLinearCombiner(result_dtype, scalar_dtype, sample_vec,
                    arg_count)
        else:
            kernel = self.make_special_linear_combiner(
                    result_dtype, scalar_dtype, sample_vec, arg_count)

            if kernel is None:
                from warnings import warn
                warn("using unoptimized linear combination routine" +
                        _NO_VPF_SUGGESTION)
                kernel = UnoptimizedLinearCombiner(result_dtype, scalar_dtype)

        if sample_is_obj_array:
            kernel = ObjectArrayLinearCombinationWrapper(kernel)

        return kernel
Пример #3
0
    def add_data(self,
                 silo,
                 variables=[],
                 scalars=[],
                 vectors=[],
                 expressions=[],
                 time=None,
                 step=None,
                 scale_factor=1):
        if scalars or vectors:
            import warnings
            warnings.warn("`scalars' and `vectors' arguments are deprecated",
                          DeprecationWarning)
            variables = scalars + vectors

        from pyvisfile.silo import DB_NODECENT, DBOPT_DTIME, DBOPT_CYCLE

        # put mesh coordinates
        mesh_opts = {}
        if time is not None:
            mesh_opts[DBOPT_DTIME] = float(time)
        if step is not None:
            mesh_opts[DBOPT_CYCLE] = int(step)

        if self.dim == 1:
            for name, field in variables:
                from hedge.tools import is_obj_array
                if is_obj_array(field):
                    AXES = ["x", "y", "z", "w"]
                    for i, f_i in enumerate(field):
                        silo.put_curve(name + AXES[i], self.xvals,
                                       scale_factor * f_i, mesh_opts)
                else:
                    silo.put_curve(name, self.xvals, scale_factor * field,
                                   mesh_opts)
        else:
            self.fine_mesh.put_mesh(silo, "finezonelist", "finemesh",
                                    mesh_opts)
            self.coarse_mesh.put_mesh(silo, "coarsezonelist", "mesh",
                                      mesh_opts)

            from hedge.tools import log_shape

            # put data
            for name, field in variables:
                ls = log_shape(field)
                if ls != () and ls[0] > 1:
                    assert len(ls) == 1
                    silo.put_ucdvar(
                        name, "finemesh",
                        ["%s_comp%d" % (name, i) for i in range(ls[0])],
                        scale_factor * field, DB_NODECENT)
                else:
                    if ls != ():
                        field = field[0]
                    silo.put_ucdvar1(name, "finemesh", scale_factor * field,
                                     DB_NODECENT)

        if expressions:
            silo.put_defvars("defvars", expressions)
Пример #4
0
 def sub_bdry_into_flux(expr):
     if isinstance(expr, FieldComponent) and not expr.is_interior:
         if expr.index == 0 and not is_obj_array(bdry_field):
             return new_bdry_field
         else:
             return new_bdry_field[expr.index]
     else:
         return None
Пример #5
0
 def sub_bdry_into_flux(expr):
     if isinstance(expr, FieldComponent) and not expr.is_interior:
         if expr.index == 0 and not is_obj_array(bdry_field):
             return new_bdry_field
         else:
             return new_bdry_field[expr.index]
     else:
         return None
Пример #6
0
def dot_dataflow_graph(code, max_node_label_length=30, 
        label_wrap_width=50):
    origins = {}
    node_names = {}

    result = [
            "initial [label=\"initial\"]"
            "result [label=\"result\"]"]

    for num, insn in enumerate(code.instructions):
        node_name = "node%d" % num
        node_names[insn] = node_name
        node_label = str(insn)

        if max_node_label_length is not None:
            node_label = node_label[:max_node_label_length]

        if label_wrap_width is not None:
            from pytools import word_wrap
            node_label = word_wrap(node_label, label_wrap_width,
                    wrap_using="\n      ")

        node_label = node_label.replace("\n", "\\l") + "\\l"

        result.append("%s [ label=\"p%d: %s\" shape=box ];" % (
            node_name, insn.priority, node_label))

        for assignee in insn.get_assignees():
            origins[assignee] = node_name

    def get_orig_node(expr):
        from pymbolic.primitives import Variable
        if isinstance(expr, Variable):
            return origins.get(expr.name, "initial")
        else:
            return "initial"

    def gen_expr_arrow(expr, target_node):
        result.append("%s -> %s [label=\"%s\"];"
                % (get_orig_node(expr), target_node, expr))

    for insn in code.instructions:
        for dep in insn.get_dependencies():
            gen_expr_arrow(dep, node_names[insn])

    from hedge.tools import is_obj_array

    if is_obj_array(code.result):
        for subexp in code.result:
            gen_expr_arrow(subexp, "result")
    else:
        gen_expr_arrow(code.result, "result")

    return "digraph dataflow {\n%s\n}\n" % "\n".join(result)
Пример #7
0
def dot_dataflow_graph(code, max_node_label_length=30, label_wrap_width=50):
    origins = {}
    node_names = {}

    result = ["initial [label=\"initial\"]" "result [label=\"result\"]"]

    for num, insn in enumerate(code.instructions):
        node_name = "node%d" % num
        node_names[insn] = node_name
        node_label = str(insn)

        if max_node_label_length is not None:
            node_label = node_label[:max_node_label_length]

        if label_wrap_width is not None:
            from pytools import word_wrap
            node_label = word_wrap(node_label,
                                   label_wrap_width,
                                   wrap_using="\n      ")

        node_label = node_label.replace("\n", "\\l") + "\\l"

        result.append("%s [ label=\"p%d: %s\" shape=box ];" %
                      (node_name, insn.priority, node_label))

        for assignee in insn.get_assignees():
            origins[assignee] = node_name

    def get_orig_node(expr):
        from pymbolic.primitives import Variable
        if isinstance(expr, Variable):
            return origins.get(expr.name, "initial")
        else:
            return "initial"

    def gen_expr_arrow(expr, target_node):
        result.append("%s -> %s [label=\"%s\"];" %
                      (get_orig_node(expr), target_node, expr))

    for insn in code.instructions:
        for dep in insn.get_dependencies():
            gen_expr_arrow(dep, node_names[insn])

    from hedge.tools import is_obj_array

    if is_obj_array(code.result):
        for subexp in code.result:
            gen_expr_arrow(subexp, "result")
    else:
        gen_expr_arrow(code.result, "result")

    return "digraph dataflow {\n%s\n}\n" % "\n".join(result)
Пример #8
0
def get_flux_operator(flux):
    """Return a flux operator that can be multiplied with
    a volume field to obtain the interior fluxes
    or with a :class:`BoundaryPair` to obtain the lifted boundary
    flux.
    """
    from hedge.tools import is_obj_array
    from hedge.optemplate import VectorFluxOperator, FluxOperator

    if is_obj_array(flux):
        return VectorFluxOperator(flux)
    else:
        return FluxOperator(flux)
Пример #9
0
def get_flux_operator(flux):
    """Return a flux operator that can be multiplied with
    a volume field to obtain the interior fluxes
    or with a :class:`BoundaryPair` to obtain the lifted boundary
    flux.
    """
    from hedge.tools import is_obj_array
    from hedge.optemplate import VectorFluxOperator, FluxOperator

    if is_obj_array(flux):
        return VectorFluxOperator(flux)
    else:
        return FluxOperator(flux)
Пример #10
0
    def add_data(self, silo, variables=[], scalars=[], vectors=[], expressions=[],
            time=None, step=None, scale_factor=1):
        if scalars or vectors:
            import warnings
            warnings.warn("`scalars' and `vectors' arguments are deprecated",
                    DeprecationWarning)
            variables = scalars + vectors

        from pyvisfile.silo import DB_NODECENT, DBOPT_DTIME, DBOPT_CYCLE

        # put mesh coordinates
        mesh_opts = {}
        if time is not None:
            mesh_opts[DBOPT_DTIME] = float(time)
        if step is not None:
            mesh_opts[DBOPT_CYCLE] = int(step)

        if self.dim == 1:
            for name, field in variables:
                from hedge.tools import is_obj_array
                if is_obj_array(field):
                    AXES = ["x", "y", "z", "w"]
                    for i, f_i in enumerate(field):
                        silo.put_curve(name+AXES[i], self.xvals,
                                scale_factor*f_i, mesh_opts)
                else:
                    silo.put_curve(name, self.xvals,
                            scale_factor*field, mesh_opts)
        else:
            self.fine_mesh.put_mesh(silo, "finezonelist", "finemesh", mesh_opts)
            self.coarse_mesh.put_mesh(silo, "coarsezonelist", "mesh", mesh_opts)

            from hedge.tools import log_shape

            # put data
            for name, field in variables:
                ls = log_shape(field)
                if ls != () and ls[0] > 1:
                    assert len(ls) == 1
                    silo.put_ucdvar(name, "finemesh",
                            ["%s_comp%d" % (name, i)
                                for i in range(ls[0])],
                            scale_factor*field, DB_NODECENT)
                else:
                    if ls != ():
                        field = field[0]
                    silo.put_ucdvar1(
                            name, "finemesh", scale_factor*field, DB_NODECENT)

        if expressions:
            silo.put_defvars("defvars", expressions)
Пример #11
0
                def func_on_scalar_or_vector(func, arg_fields):
                    # No CSE necessary here--the compiler CSE's these
                    # automatically.

                    from hedge.tools import is_obj_array, make_obj_array
                    if is_obj_array(arg_fields):
                        # arg_fields (as an object array) isn't hashable
                        # --make it so by turning it into a tuple
                        arg_fields = tuple(arg_fields)

                        return make_obj_array([
                            func(i, arg_fields) for i in range(len(arg_fields))
                        ])
                    else:
                        return func(0, (arg_fields, ))
Пример #12
0
                def func_on_scalar_or_vector(func, arg_fields):
                    # No CSE necessary here--the compiler CSE's these
                    # automatically.

                    from hedge.tools import is_obj_array, make_obj_array
                    if is_obj_array(arg_fields):
                        # arg_fields (as an object array) isn't hashable
                        # --make it so by turning it into a tuple
                        arg_fields = tuple(arg_fields)

                        return make_obj_array([
                            func(i, arg_fields)
                            for i in range(len(arg_fields))])
                    else:
                        return func(0, (arg_fields,))
Пример #13
0
    def make_inner_product(self, sample_vec):
        from hedge.tools import is_obj_array
        sample_is_obj_array = is_obj_array(sample_vec)

        if sample_is_obj_array:
            sample_vec = sample_vec[0]

        if isinstance(sample_vec, numpy.ndarray) and sample_vec.dtype != object:
            kernel = numpy.dot
        else:
            kernel = self.make_special_inner_product(sample_vec)

            if kernel is None:
                raise RuntimeError("could not find an inner product routine for "
                        "the given sample vector" + _NO_VPF_SUGGESTION)
        if sample_is_obj_array:
            kernel = ObjectArrayInnerProductWrapper(kernel)

        return kernel
Пример #14
0
    def make_inner_product(self, sample_vec):
        from hedge.tools import is_obj_array
        sample_is_obj_array = is_obj_array(sample_vec)

        if sample_is_obj_array:
            sample_vec = sample_vec[0]

        if isinstance(sample_vec, numpy.ndarray) and sample_vec.dtype != object:
            kernel = numpy.dot
        else:
            kernel = self.make_special_inner_product(sample_vec)

            if kernel is None:
                raise RuntimeError("could not find an inner product routine for "
                        "the given sample vector" + _NO_VPF_SUGGESTION)
        if sample_is_obj_array:
            kernel = ObjectArrayInnerProductWrapper(kernel)

        return kernel
Пример #15
0
    def map_field_component(self, expr):
        if expr.is_interior:
            prefix = "a"
            f_expr = self.int_field_expr
        else:
            prefix = "b"
            f_expr = self.ext_field_expr

        from hedge.tools import is_obj_array, is_zero
        from pymbolic import var
        if is_obj_array(f_expr):
            f_expr = f_expr[expr.index]
            if is_zero(f_expr):
                return 0
            return var("val_%s_field%d" % (prefix, self.dep_to_index[f_expr]))
        else:
            assert expr.index == 0, repr(f_expr)
            if is_zero(f_expr):
                return 0
            return var("val_%s_field%d" % (prefix, self.dep_to_index[f_expr]))
Пример #16
0
    def make_maximum_norm(self, sample_vec):
        from hedge.tools import is_obj_array
        sample_is_obj_array = is_obj_array(sample_vec)

        if sample_is_obj_array:
            sample_vec = sample_vec[0]

        if isinstance(sample_vec, numpy.ndarray) and sample_vec.dtype != object:
            kernel = numpy.max
        else:
            kernel = self.make_special_maximum_norm(sample_vec)

            if kernel is None:
                raise RuntimeError("could not find a maximum norm routine for "
                        "the given sample vector" + _NO_VPF_SUGGESTION)

        if sample_is_obj_array:
            kernel = ObjectArrayMaximumNormWrapper(kernel)

        return kernel
Пример #17
0
    def map_field_component(self, expr):
        if expr.is_interior:
            prefix = "a"
            f_expr = self.int_field_expr
        else:
            prefix = "b"
            f_expr = self.ext_field_expr

        from hedge.tools import is_obj_array, is_zero
        from pymbolic import var
        if is_obj_array(f_expr):
            f_expr = f_expr[expr.index]
            if is_zero(f_expr):
                return 0
            return var("val_%s_field%d" % (prefix, self.dep_to_index[f_expr]))
        else:
            assert expr.index == 0, repr(f_expr)
            if is_zero(f_expr):
                return 0
            return var("val_%s_field%d" % (prefix, self.dep_to_index[f_expr]))
Пример #18
0
 def maybe_index(fld, index):
     from hedge.tools import is_obj_array
     if is_obj_array(fld):
         return fld[inf.index]
     else:
         return fld
Пример #19
0
def get_flux_var_info(fluxes):
    from pytools import Record
    class FluxVariableInfo(Record):
        pass

    scalar_parameters = set()

    fvi = FluxVariableInfo(
            scalar_parameters=None,
            arg_specs=[],
            arg_names=[],
            flux_idx_and_dep_to_arg_name={}, # or 0 if zero
            )

    field_expr_to_arg_name = {}

    from hedge.flux import \
            FieldComponent, FluxDependencyMapper, \
            FluxScalarParameter

    from hedge.optemplate import BoundaryPair

    for flux_idx, flux_binding in enumerate(fluxes):
        for dep in FluxDependencyMapper(include_calls=False)(flux_binding.op.flux):
            if isinstance(dep, FluxScalarParameter):
                scalar_parameters.add(dep)
            elif isinstance(dep, FieldComponent):
                is_bdry = isinstance(flux_binding.field, BoundaryPair)
                if is_bdry:
                    if dep.is_interior:
                        this_field_expr = flux_binding.field.field
                    else:
                        this_field_expr = flux_binding.field.bfield
                else:
                    this_field_expr = flux_binding.field

                from hedge.tools import is_obj_array
                if is_obj_array(this_field_expr):
                    fc_field_expr = this_field_expr[dep.index]
                else:
                    assert dep.index == 0
                    fc_field_expr = this_field_expr

                def set_or_check(dict_instance, key, value):
                    try:
                        existing_value = dict_instance[key]
                    except KeyError:
                        dict_instance[key] = value
                    else:
                        assert existing_value == value

                from pymbolic.primitives import is_zero
                if is_zero(fc_field_expr):
                    fvi.flux_idx_and_dep_to_arg_name[flux_idx, dep] = 0
                else:
                    if fc_field_expr not in field_expr_to_arg_name:
                        arg_name = "arg%d" % len(fvi.arg_specs)
                        field_expr_to_arg_name[fc_field_expr] = arg_name

                        fvi.arg_names.append(arg_name)
                        fvi.arg_specs.append((fc_field_expr, dep.is_interior))
                    else:
                        arg_name = field_expr_to_arg_name[fc_field_expr]

                    set_or_check(
                            fvi.flux_idx_and_dep_to_arg_name,
                            (flux_idx, dep),
                            arg_name)

                    if not is_bdry:
                        # Interior fluxes are used flipped as well.
                        # Make sure we have assigned arg names for the
                        # flipped case as well.
                        set_or_check(
                                fvi.flux_idx_and_dep_to_arg_name,
                                (flux_idx,
                                    FieldComponent(dep.index, not dep.is_interior)),
                                arg_name)
            else:
                raise ValueError("unknown flux dependency type: %s" % dep)

    fvi.scalar_parameters = list(scalar_parameters)

    return fvi
Пример #20
0
    def aggregate_assignments(self, instructions, result):
        from pymbolic.primitives import Variable

        # {{{ aggregation helpers

        def get_complete_origins_set(insn, skip_levels=0):
            if skip_levels < 0:
                skip_levels = 0

            result = set()
            for dep in insn.get_dependencies():
                if isinstance(dep, Variable):
                    dep_origin = origins_map.get(dep.name, None)
                    if dep_origin is not None:
                        if skip_levels <= 0:
                            result.add(dep_origin)
                        result |= get_complete_origins_set(
                            dep_origin, skip_levels - 1)

            return result

        var_assignees_cache = {}

        def get_var_assignees(insn):
            try:
                return var_assignees_cache[insn]
            except KeyError:
                result = set(
                    Variable(assignee) for assignee in insn.get_assignees())
                var_assignees_cache[insn] = result
                return result

        def aggregate_two_assignments(ass_1, ass_2):
            names = ass_1.names + ass_2.names

            from pymbolic.primitives import Variable
            deps = (ass_1.get_dependencies() | ass_2.get_dependencies()) \
                    - set(Variable(name) for name in names)

            return Assign(names=names,
                          exprs=ass_1.exprs + ass_2.exprs,
                          _dependencies=deps,
                          dep_mapper_factory=self.dep_mapper_factory,
                          priority=max(ass_1.priority, ass_2.priority))

        # }}}

        # {{{ main aggregation pass

        origins_map = dict((assignee, insn) for insn in instructions
                           for assignee in insn.get_assignees())

        from pytools import partition
        unprocessed_assigns, other_insns = partition(
            lambda insn: isinstance(insn, Assign) and not insn.
            is_scalar_valued, instructions)

        # filter out zero-flop-count assigns--no need to bother with those
        processed_assigns, unprocessed_assigns = partition(
            lambda ass: ass.flop_count() == 0, unprocessed_assigns)

        # filter out zero assignments
        from pytools import any
        from hedge.tools import is_zero

        i = 0

        while i < len(unprocessed_assigns):
            my_assign = unprocessed_assigns[i]
            if any(is_zero(expr) for expr in my_assign.exprs):
                processed_assigns.append(unprocessed_assigns.pop())
            else:
                i += 1

        # greedy aggregation
        while unprocessed_assigns:
            my_assign = unprocessed_assigns.pop()

            my_deps = my_assign.get_dependencies()
            my_assignees = get_var_assignees(my_assign)

            agg_candidates = []
            for i, other_assign in enumerate(unprocessed_assigns):
                other_deps = other_assign.get_dependencies()
                other_assignees = get_var_assignees(other_assign)

                if ((my_deps & other_deps or my_deps & other_assignees
                     or other_deps & my_assignees)
                        and my_assign.priority == other_assign.priority):
                    agg_candidates.append((i, other_assign))

            did_work = False

            if agg_candidates:
                my_indirect_origins = get_complete_origins_set(my_assign,
                                                               skip_levels=1)

                for other_assign_index, other_assign in agg_candidates:
                    if self.max_vectors_in_batch_expr is not None:
                        new_assignee_count = len(
                            set(my_assign.get_assignees())
                            | set(other_assign.get_assignees()))
                        new_dep_count = len(
                            my_assign.get_dependencies(each_vector=True)
                            | other_assign.get_dependencies(each_vector=True))

                        if (new_assignee_count + new_dep_count >
                                self.max_vectors_in_batch_expr):
                            continue

                    other_indirect_origins = get_complete_origins_set(
                        other_assign, skip_levels=1)

                    if (my_assign not in other_indirect_origins
                            and other_assign not in my_indirect_origins):
                        did_work = True

                        # aggregate the two assignments
                        new_assignment = aggregate_two_assignments(
                            my_assign, other_assign)
                        del unprocessed_assigns[other_assign_index]
                        unprocessed_assigns.append(new_assignment)
                        for assignee in new_assignment.get_assignees():
                            origins_map[assignee] = new_assignment

                        break

            if not did_work:
                processed_assigns.append(my_assign)

        externally_used_names = set(expr
                                    for insn in processed_assigns + other_insns
                                    for expr in insn.get_dependencies())

        from hedge.tools import is_obj_array
        if is_obj_array(result):
            externally_used_names |= set(expr for expr in result)
        else:
            externally_used_names |= set([result])

        def schedule_and_finalize_assignment(ass):
            dep_mapper = self.dep_mapper_factory()

            names_exprs = zip(ass.names, ass.exprs)

            my_assignees = set(name for name, expr in names_exprs)
            names_exprs_deps = [
                (name, expr,
                 set(dep.name
                     for dep in dep_mapper(expr) if isinstance(dep, Variable))
                 & my_assignees) for name, expr in names_exprs
            ]

            ordered_names_exprs = []
            available_names = set()

            while names_exprs_deps:
                schedulable = []

                i = 0
                while i < len(names_exprs_deps):
                    name, expr, deps = names_exprs_deps[i]

                    unsatisfied_deps = deps - available_names

                    if not unsatisfied_deps:
                        schedulable.append((str(expr), name, expr))
                        del names_exprs_deps[i]
                    else:
                        i += 1

                # make sure these come out in a constant order
                schedulable.sort()

                if schedulable:
                    for key, name, expr in schedulable:
                        ordered_names_exprs.append((name, expr))
                        available_names.add(name)
                else:
                    raise RuntimeError("aggregation resulted in an "
                                       "impossible assignment")

            return self.finalize_multi_assign(
                names=[name for name, expr in ordered_names_exprs],
                exprs=[expr for name, expr in ordered_names_exprs],
                do_not_return=[
                    Variable(name) not in externally_used_names
                    for name, expr in ordered_names_exprs
                ],
                priority=ass.priority)

        return [
            schedule_and_finalize_assignment(ass) for ass in processed_assigns
        ] + other_insns
Пример #21
0
 def get_deps(field):
     if is_obj_array(field):
         return set(field)
     else:
         return set([field])
Пример #22
0
 def maybe_index(fld, index):
     from hedge.tools import is_obj_array
     if is_obj_array(fld):
         return fld[inf.index]
     else:
         return fld
Пример #23
0
    def aggregate_assignments(self, instructions, result):
        from pymbolic.primitives import Variable

        # aggregation helpers -------------------------------------------------
        def get_complete_origins_set(insn, skip_levels=0):
            if skip_levels < 0:
                skip_levels = 0

            result = set()
            for dep in insn.get_dependencies():
                if isinstance(dep, Variable):
                    dep_origin = origins_map.get(dep.name, None)
                    if dep_origin is not None:
                        if skip_levels <= 0:
                            result.add(dep_origin)
                        result |= get_complete_origins_set(
                                dep_origin, skip_levels-1)

            return result

        var_assignees_cache = {}
        def get_var_assignees(insn):
            try:
                return var_assignees_cache[insn]
            except KeyError:
                result = set(Variable(assignee)
                        for assignee in insn.get_assignees())
                var_assignees_cache[insn] = result
                return result

        def aggregate_two_assignments(ass_1, ass_2):
            names = ass_1.names + ass_2.names

            from pymbolic.primitives import Variable
            deps = (ass_1.get_dependencies() | ass_2.get_dependencies()) \
                    - set(Variable(name) for name in names)

            return Assign(
                    names=names, exprs=ass_1.exprs + ass_2.exprs,
                    _dependencies=deps,
                    dep_mapper_factory=self.dep_mapper_factory,
                    priority=max(ass_1.priority, ass_2.priority))

        # main aggregation pass -----------------------------------------------
        origins_map = dict(
                    (assignee, insn)
                    for insn in instructions
                    for assignee in insn.get_assignees())

        from pytools import partition
        unprocessed_assigns, other_insns = partition(
                lambda insn: isinstance(insn, Assign),
                instructions)

        # filter out zero-flop-count assigns--no need to bother with those
        processed_assigns, unprocessed_assigns = partition(
                lambda ass: ass.flop_count() == 0,
                unprocessed_assigns)

        # filter out zero assignments
        from pytools import any
        from hedge.tools import is_zero

        i = 0

        while i < len(unprocessed_assigns):
            my_assign = unprocessed_assigns[i]
            if any(is_zero(expr) for expr in my_assign.exprs):
                processed_assigns.append(unprocessed_assigns.pop())
            else:
                i += 1

        # greedy aggregation
        while unprocessed_assigns:
            my_assign = unprocessed_assigns.pop()

            my_deps = my_assign.get_dependencies()
            my_assignees = get_var_assignees(my_assign)

            agg_candidates = []
            for i, other_assign in enumerate(unprocessed_assigns):
                other_deps = other_assign.get_dependencies()
                other_assignees = get_var_assignees(other_assign)

                if ((my_deps & other_deps
                        or my_deps & other_assignees
                        or other_deps & my_assignees)
                        and my_assign.priority == other_assign.priority):
                    agg_candidates.append((i, other_assign))

            did_work = False

            if agg_candidates:
                my_indirect_origins = get_complete_origins_set(
                        my_assign, skip_levels=1)

                for other_assign_index, other_assign in agg_candidates:
                    if self.max_vectors_in_batch_expr is not None:
                        new_assignee_count = len(
                                set(my_assign.get_assignees())
                                | set(other_assign.get_assignees()))
                        new_dep_count = len(
                                my_assign.get_dependencies(
                                    each_vector=True)
                                | other_assign.get_dependencies(
                                    each_vector=True))

                        if (new_assignee_count + new_dep_count \
                                > self.max_vectors_in_batch_expr):
                            continue

                    other_indirect_origins = get_complete_origins_set(
                            other_assign, skip_levels=1)

                    if (my_assign not in other_indirect_origins and
                            other_assign not in my_indirect_origins):
                        did_work = True

                        # aggregate the two assignments
                        new_assignment = aggregate_two_assignments(
                                my_assign, other_assign)
                        del unprocessed_assigns[other_assign_index]
                        unprocessed_assigns.append(new_assignment)
                        for assignee in new_assignment.get_assignees():
                            origins_map[assignee] = new_assignment

                        break

            if not did_work:
                processed_assigns.append(my_assign)

        externally_used_names = set(
                expr
                for insn in processed_assigns + other_insns
                for expr in insn.get_dependencies())

        from hedge.tools import is_obj_array
        if is_obj_array(result):
            externally_used_names |= set(expr for expr in result)
        else:
            externally_used_names |= set([result])

        def schedule_and_finalize_assignment(ass):
            dep_mapper = self.dep_mapper_factory()

            names_exprs = zip(ass.names, ass.exprs)

            my_assignees = set(name for name, expr in names_exprs)
            names_exprs_deps = [
                    (name, expr,
                        set(dep.name for dep in dep_mapper(expr) if
                            isinstance(dep, Variable)) & my_assignees)
                    for name, expr in names_exprs]

            ordered_names_exprs = []
            available_names = set()

            while names_exprs_deps:
                schedulable = []

                i = 0
                while i < len(names_exprs_deps):
                    name, expr, deps = names_exprs_deps[i]

                    unsatisfied_deps = deps - available_names

                    if not unsatisfied_deps:
                        schedulable.append((str(expr), name, expr))
                        del names_exprs_deps[i]
                    else:
                        i += 1

                # make sure these come out in a constant order
                schedulable.sort()

                if schedulable:
                    for key, name, expr in schedulable:
                        ordered_names_exprs.append((name, expr))
                        available_names.add(name)
                else:
                    raise RuntimeError("aggregation resulted in an "
                            "impossible assignment")

            return self.finalize_multi_assign(
                    names=[name for name, expr in ordered_names_exprs],
                    exprs=[expr for name, expr in ordered_names_exprs],
                    do_not_return=[Variable(name) not in externally_used_names
                        for name, expr in ordered_names_exprs],
                    priority=ass.priority)

        return [schedule_and_finalize_assignment(ass)
            for ass in processed_assigns] + other_insns
Пример #24
0
    def map_operator_binding(self, expr):
        from hedge.optemplate.operators import FluxOperatorBase
        from hedge.optemplate.primitives import BoundaryPair
        from hedge.flux import FluxSubstitutionMapper, FieldComponent

        if not (isinstance(expr.op, FluxOperatorBase)
                and isinstance(expr.field, BoundaryPair)):
            return IdentityMapper.map_operator_binding(self, expr)

        bpair = expr.field
        vol_field = bpair.field
        bdry_field = bpair.bfield
        flux = expr.op.flux

        bdry_dependencies = DependencyMapper(
            include_calls="descend_args",
            include_operator_bindings=True)(bdry_field)

        vol_dependencies = DependencyMapper(
            include_operator_bindings=True)(vol_field)

        vol_bdry_intersection = bdry_dependencies & vol_dependencies
        if vol_bdry_intersection:
            raise RuntimeError(
                "Variables are being used as both "
                "boundary and volume quantities: %s" %
                ", ".join(str(v) for v in vol_bdry_intersection))

        # Step 1: Find maximal flux-evaluable subexpression of boundary field
        # in given BoundaryPair.

        class MaxBoundaryFluxEvaluableExpressionFinder(IdentityMapper,
                                                       OperatorReducerMixin):
            def __init__(self, vol_expr_list, expensive_bdry_op_detector):
                self.vol_expr_list = vol_expr_list
                self.vol_expr_to_idx = dict(
                    (vol_expr, idx)
                    for idx, vol_expr in enumerate(vol_expr_list))

                self.bdry_expr_list = []
                self.bdry_expr_to_idx = {}

                self.expensive_bdry_op_detector = expensive_bdry_op_detector

            # {{{ expression registration
            def register_boundary_expr(self, expr):
                try:
                    return self.bdry_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.bdry_expr_to_idx)
                    self.bdry_expr_to_idx[expr] = idx
                    self.bdry_expr_list.append(expr)
                    return idx

            def register_volume_expr(self, expr):
                try:
                    return self.vol_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.vol_expr_to_idx)
                    self.vol_expr_to_idx[expr] = idx
                    self.vol_expr_list.append(expr)
                    return idx

            # }}}

            # {{{ map_xxx routines

            @memoize_method
            def map_common_subexpression(self, expr):
                # Here we need to decide whether this CSE should be turned into
                # a flux CSE or not. This is a good idea if the transformed
                # expression only contains "bare" volume or boundary
                # expressions.  However, as soon as an operator is applied
                # somewhere in the subexpression, the CSE should not be touched
                # in order to avoid redundant evaluation of that operator.
                #
                # Observe that at the time of this writing (Feb 2010), the only
                # operators that may occur in boundary expressions are
                # quadrature-related.

                has_expensive_operators = \
                        self.expensive_bdry_op_detector(expr.child)

                if has_expensive_operators:
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)
                else:
                    return IdentityMapper.map_common_subexpression(self, expr)

            def map_normal(self, expr):
                raise RuntimeError(
                    "Your operator template contains a flux normal. "
                    "You may find this confusing, but you can't do that. "
                    "It turns out that you need to use "
                    "hedge.optemplate.make_normal() for normals in boundary "
                    "terms of operator templates.")

            def map_normal_component(self, expr):
                if expr.boundary_tag != bpair.tag:
                    raise RuntimeError(
                        "BoundaryNormalComponent and BoundaryPair "
                        "do not agree about boundary tag: %s vs %s" %
                        (expr.boundary_tag, bpair.tag))

                from hedge.flux import Normal
                return Normal(expr.axis)

            def map_variable(self, expr):
                return FieldComponent(self.register_boundary_expr(expr),
                                      is_interior=False)

            map_subscript = map_variable

            def map_operator_binding(self, expr):
                from hedge.optemplate import (BoundarizeOperator,
                                              FluxExchangeOperator,
                                              QuadratureGridUpsampler,
                                              QuadratureBoundaryGridUpsampler)

                if isinstance(expr.op, BoundarizeOperator):
                    if expr.op.tag != bpair.tag:
                        raise RuntimeError(
                            "BoundarizeOperator and BoundaryPair "
                            "do not agree about boundary tag: %s vs %s" %
                            (expr.op.tag, bpair.tag))

                    return FieldComponent(self.register_volume_expr(
                        expr.field),
                                          is_interior=True)

                elif isinstance(expr.op, FluxExchangeOperator):
                    from hedge.mesh import TAG_RANK_BOUNDARY
                    op_tag = TAG_RANK_BOUNDARY(expr.op.rank)
                    if bpair.tag != op_tag:
                        raise RuntimeError(
                            "BoundarizeOperator and "
                            "FluxExchangeOperator do not agree about "
                            "boundary tag: %s vs %s" % (op_tag, bpair.tag))
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)

                elif isinstance(expr.op, QuadratureBoundaryGridUpsampler):
                    if bpair.tag != expr.op.boundary_tag:
                        raise RuntimeError(
                            "BoundarizeOperator "
                            "and QuadratureBoundaryGridUpsampler "
                            "do not agree about boundary tag: %s vs %s" %
                            (expr.op.boundary_tag, bpair.tag))
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)

                elif isinstance(expr.op, QuadratureGridUpsampler):
                    # We're invoked before operator specialization, so we may
                    # see these instead of QuadratureBoundaryGridUpsampler.
                    return FieldComponent(self.register_boundary_expr(expr),
                                          is_interior=False)

                else:
                    raise RuntimeError(
                        "Found '%s' in a boundary term. "
                        "To the best of my knowledge, no hedge operator applies "
                        "directly to boundary data, so this is likely in error."
                        % expr.op)

            def map_flux_exchange(self, expr):
                return FieldComponent(self.register_boundary_expr(expr),
                                      is_interior=False)

            # }}}

        from hedge.tools import is_obj_array
        if not is_obj_array(vol_field):
            vol_field = [vol_field]

        mbfeef = MaxBoundaryFluxEvaluableExpressionFinder(
            list(vol_field), self.expensive_bdry_op_detector)
        #from hedge.optemplate.tools import pretty
        #print pretty(bdry_field)
        #raw_input("YO")
        new_bdry_field = mbfeef(bdry_field)

        # Step II: Substitute the new_bdry_field into the flux.
        def sub_bdry_into_flux(expr):
            if isinstance(expr, FieldComponent) and not expr.is_interior:
                if expr.index == 0 and not is_obj_array(bdry_field):
                    return new_bdry_field
                else:
                    return new_bdry_field[expr.index]
            else:
                return None

        new_flux = FluxSubstitutionMapper(sub_bdry_into_flux)(flux)

        from hedge.tools import is_zero, make_obj_array
        if is_zero(new_flux):
            return 0
        else:
            return type(expr.op)(new_flux, *expr.op.__getinitargs__()[1:])(
                BoundaryPair(
                    make_obj_array([self.rec(e)
                                    for e in mbfeef.vol_expr_list]),
                    make_obj_array(
                        [self.rec(e) for e in mbfeef.bdry_expr_list]),
                    bpair.tag))
Пример #25
0
    def map_operator_binding(self, expr):
        from hedge.optemplate.operators import FluxOperatorBase
        from hedge.optemplate.primitives import BoundaryPair
        from hedge.flux import FluxSubstitutionMapper, FieldComponent

        if not (isinstance(expr.op, FluxOperatorBase)
                and isinstance(expr.field, BoundaryPair)):
            return IdentityMapper.map_operator_binding(self, expr)

        bpair = expr.field
        vol_field = bpair.field
        bdry_field = bpair.bfield
        flux = expr.op.flux

        bdry_dependencies = DependencyMapper(
                    include_calls="descend_args",
                    include_operator_bindings=True)(bdry_field)

        vol_dependencies = DependencyMapper(
                include_operator_bindings=True)(vol_field)

        vol_bdry_intersection = bdry_dependencies & vol_dependencies
        if vol_bdry_intersection:
            raise RuntimeError("Variables are being used as both "
                    "boundary and volume quantities: %s"
                    % ", ".join(str(v) for v in vol_bdry_intersection))

        # Step 1: Find maximal flux-evaluable subexpression of boundary field
        # in given BoundaryPair.

        class MaxBoundaryFluxEvaluableExpressionFinder(
                IdentityMapper, OperatorReducerMixin):

            def __init__(self, vol_expr_list, expensive_bdry_op_detector):
                self.vol_expr_list = vol_expr_list
                self.vol_expr_to_idx = dict((vol_expr, idx)
                        for idx, vol_expr in enumerate(vol_expr_list))

                self.bdry_expr_list = []
                self.bdry_expr_to_idx = {}

                self.expensive_bdry_op_detector = expensive_bdry_op_detector

            # {{{ expression registration
            def register_boundary_expr(self, expr):
                try:
                    return self.bdry_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.bdry_expr_to_idx)
                    self.bdry_expr_to_idx[expr] = idx
                    self.bdry_expr_list.append(expr)
                    return idx

            def register_volume_expr(self, expr):
                try:
                    return self.vol_expr_to_idx[expr]
                except KeyError:
                    idx = len(self.vol_expr_to_idx)
                    self.vol_expr_to_idx[expr] = idx
                    self.vol_expr_list.append(expr)
                    return idx

            # }}}

            # {{{ map_xxx routines

            @memoize_method
            def map_common_subexpression(self, expr):
                # Here we need to decide whether this CSE should be turned into
                # a flux CSE or not. This is a good idea if the transformed
                # expression only contains "bare" volume or boundary
                # expressions.  However, as soon as an operator is applied
                # somewhere in the subexpression, the CSE should not be touched
                # in order to avoid redundant evaluation of that operator.
                #
                # Observe that at the time of this writing (Feb 2010), the only
                # operators that may occur in boundary expressions are
                # quadrature-related.

                has_expensive_operators = \
                        self.expensive_bdry_op_detector(expr.child)

                if has_expensive_operators:
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)
                else:
                    return IdentityMapper.map_common_subexpression(self, expr)

            def map_normal(self, expr):
                raise RuntimeError("Your operator template contains a flux normal. "
                        "You may find this confusing, but you can't do that. "
                        "It turns out that you need to use "
                        "hedge.optemplate.make_normal() for normals in boundary "
                        "terms of operator templates.")

            def map_normal_component(self, expr):
                if expr.boundary_tag != bpair.tag:
                    raise RuntimeError("BoundaryNormalComponent and BoundaryPair "
                            "do not agree about boundary tag: %s vs %s"
                            % (expr.boundary_tag, bpair.tag))

                from hedge.flux import Normal
                return Normal(expr.axis)

            def map_variable(self, expr):
                return FieldComponent(
                        self.register_boundary_expr(expr),
                        is_interior=False)

            map_subscript = map_variable

            def map_operator_binding(self, expr):
                from hedge.optemplate import (BoundarizeOperator,
                        FluxExchangeOperator,
                        QuadratureGridUpsampler,
                        QuadratureBoundaryGridUpsampler)

                if isinstance(expr.op, BoundarizeOperator):
                    if expr.op.tag != bpair.tag:
                        raise RuntimeError("BoundarizeOperator and BoundaryPair "
                                "do not agree about boundary tag: %s vs %s"
                                % (expr.op.tag, bpair.tag))

                    return FieldComponent(
                            self.register_volume_expr(expr.field),
                            is_interior=True)

                elif isinstance(expr.op, FluxExchangeOperator):
                    from hedge.mesh import TAG_RANK_BOUNDARY
                    op_tag = TAG_RANK_BOUNDARY(expr.op.rank)
                    if bpair.tag != op_tag:
                        raise RuntimeError("BoundarizeOperator and FluxExchangeOperator "
                                "do not agree about boundary tag: %s vs %s"
                                % (op_tag, bpair.tag))
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)

                elif isinstance(expr.op, QuadratureBoundaryGridUpsampler):
                    if bpair.tag != expr.op.boundary_tag:
                        raise RuntimeError("BoundarizeOperator "
                                "and QuadratureBoundaryGridUpsampler "
                                "do not agree about boundary tag: %s vs %s"
                                % (expr.op.boundary_tag, bpair.tag))
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)

                elif isinstance(expr.op, QuadratureGridUpsampler):
                    # We're invoked before operator specialization, so we may
                    # see these instead of QuadratureBoundaryGridUpsampler.
                    return FieldComponent(
                            self.register_boundary_expr(expr),
                            is_interior=False)

                else:
                    raise RuntimeError("Found '%s' in a boundary term. "
                            "To the best of my knowledge, no hedge operator applies "
                            "directly to boundary data, so this is likely in error."
                            % expr.op)

            def map_flux_exchange(self, expr):
                return FieldComponent(
                        self.register_boundary_expr(expr),
                        is_interior=False)
            # }}}

        from hedge.tools import is_obj_array
        if not is_obj_array(vol_field):
            vol_field = [vol_field]

        mbfeef = MaxBoundaryFluxEvaluableExpressionFinder(list(vol_field),
                self.expensive_bdry_op_detector)
        #from hedge.optemplate.tools import pretty_print_optemplate
        #print pretty_print_optemplate(bdry_field)
        #raw_input("YO")
        new_bdry_field = mbfeef(bdry_field)

        # Step II: Substitute the new_bdry_field into the flux.
        def sub_bdry_into_flux(expr):
            if isinstance(expr, FieldComponent) and not expr.is_interior:
                if expr.index == 0 and not is_obj_array(bdry_field):
                    return new_bdry_field
                else:
                    return new_bdry_field[expr.index]
            else:
                return None

        new_flux = FluxSubstitutionMapper(sub_bdry_into_flux)(flux)

        from hedge.tools import is_zero, make_obj_array
        if is_zero(new_flux):
            return 0
        else:
            return type(expr.op)(new_flux, *expr.op.__getinitargs__()[1:])(
                    BoundaryPair(
                        make_obj_array([self.rec(e) for e in mbfeef.vol_expr_list]),
                        make_obj_array([self.rec(e) for e in mbfeef.bdry_expr_list]),
                        bpair.tag))
Пример #26
0
 def get_deps(field):
     if is_obj_array(field):
         return set(field)
     else:
         return set([field])
Пример #27
0
def get_flux_var_info(fluxes):
    from pytools import Record
    class FluxVariableInfo(Record):
        pass

    scalar_parameters = set()

    fvi = FluxVariableInfo(
            scalar_parameters=None,
            arg_specs=[],
            arg_names=[],
            flux_idx_and_dep_to_arg_name={}, # or 0 if zero
            )

    field_expr_to_arg_name = {}

    from hedge.flux import \
            FieldComponent, FluxDependencyMapper, \
            FluxScalarParameter

    from hedge.optemplate import BoundaryPair

    for flux_idx, flux_binding in enumerate(fluxes):
        from hedge.optemplate.primitives import CFunction
        for dep in FluxDependencyMapper(include_calls=False)(flux_binding.op.flux):
            if isinstance(dep, FluxScalarParameter):
                scalar_parameters.add(dep)
            elif isinstance(dep, FieldComponent):
                is_bdry = isinstance(flux_binding.field, BoundaryPair)
                if is_bdry:
                    if dep.is_interior:
                        this_field_expr = flux_binding.field.field
                    else:
                        this_field_expr = flux_binding.field.bfield
                else:
                    this_field_expr = flux_binding.field

                from hedge.tools import is_obj_array
                if is_obj_array(this_field_expr):
                    fc_field_expr = this_field_expr[dep.index]
                else:
                    assert dep.index == 0
                    fc_field_expr = this_field_expr

                def set_or_check(dict_instance, key, value):
                    try:
                        existing_value = dict_instance[key]
                    except KeyError:
                        dict_instance[key] = value
                    else:
                        assert existing_value == value

                from pymbolic.primitives import is_zero
                if is_zero(fc_field_expr):
                    fvi.flux_idx_and_dep_to_arg_name[flux_idx, dep] = 0
                else:
                    if fc_field_expr not in field_expr_to_arg_name:
                        arg_name = "arg%d" % len(fvi.arg_specs)
                        field_expr_to_arg_name[fc_field_expr] = arg_name

                        fvi.arg_names.append(arg_name)
                        fvi.arg_specs.append((fc_field_expr, dep.is_interior))
                    else:
                        arg_name = field_expr_to_arg_name[fc_field_expr]

                    set_or_check(
                            fvi.flux_idx_and_dep_to_arg_name,
                            (flux_idx, dep),
                            arg_name)

                    if not is_bdry:
                        # Interior fluxes are used flipped as well.
                        # Make sure we have assigned arg names for the
                        # flipped case as well.
                        set_or_check(
                                fvi.flux_idx_and_dep_to_arg_name,
                                (flux_idx,
                                    FieldComponent(dep.index, not dep.is_interior)),
                                arg_name)
            elif isinstance(dep, CFunction):
                pass
            else:
                raise ValueError("unknown flux dependency type: %s" % dep)

    fvi.scalar_parameters = list(scalar_parameters)

    return fvi