Exemple #1
0
    def get_loopy_insns_and_result_names(self):
        from sumpy.symbolic import make_sym_vector
        bvec = make_sym_vector("b", self.dim)

        import sumpy.symbolic as sp
        rscale = sp.Symbol("rscale")

        from sumpy.assignment_collection import SymbolicAssignmentCollection
        sac = SymbolicAssignmentCollection()

        coeff_exprs = [
            sym.Symbol("coeff%d" % i)
            for i in range(len(self.expansion.get_coefficient_identifiers()))
        ]
        value = self.expansion.evaluate(coeff_exprs, bvec, rscale)

        result_names = [
            sac.assign_unique("result_%d_p" % i,
                              knl.postprocess_at_target(value, bvec))
            for i, knl in enumerate(self.kernels)
        ]

        sac.run_global_cse()

        from sumpy.codegen import to_loopy_insns
        loopy_insns = to_loopy_insns(
            six.iteritems(sac.assignments),
            vector_names=set(["b"]),
            pymbolic_expr_maps=[self.expansion.get_code_transformer()],
            retain_names=result_names,
            complex_dtype=np.complex128  # FIXME
        )

        return loopy_insns, result_names
Exemple #2
0
    def get_translation_loopy_insns(self):
        from sumpy.symbolic import make_sym_vector
        dvec = make_sym_vector("d", self.dim)

        src_coeff_exprs = [sym.Symbol("src_coeff%d" % i)
                for i in range(len(self.src_expansion))]
        src_rscale = sym.Symbol("src_rscale")

        tgt_rscale = sym.Symbol("tgt_rscale")

        from sumpy.assignment_collection import SymbolicAssignmentCollection
        sac = SymbolicAssignmentCollection()
        tgt_coeff_names = [
                sac.assign_unique("coeff%d" % i, coeff_i)
                for i, coeff_i in enumerate(
                    self.tgt_expansion.translate_from(
                        self.src_expansion, src_coeff_exprs, src_rscale,
                        dvec, tgt_rscale, sac=sac))]

        sac.run_global_cse()

        from sumpy.codegen import to_loopy_insns
        return to_loopy_insns(
                six.iteritems(sac.assignments),
                vector_names=set(["d"]),
                pymbolic_expr_maps=[self.tgt_expansion.get_code_transformer()],
                retain_names=tgt_coeff_names,
                complex_dtype=np.complex128  # FIXME
                )
Exemple #3
0
def expand(expansion_nr, sac, expansion, avec, bvec):
    rscale = sym.Symbol("rscale")

    coefficients = expansion.coefficients_from_source(avec, bvec, rscale)

    assigned_coeffs = [
        sym.Symbol(
            sac.assign_unique(
                "expn%dcoeff%s" % (expansion_nr, stringify_expn_index(i)),
                coefficients[expansion.get_storage_index(i)]))
        for i in expansion.get_coefficient_identifiers()
    ]

    return sac.assign_unique("expn%d_result" % expansion_nr,
                             expansion.evaluate(assigned_coeffs, bvec, rscale))
Exemple #4
0
    def try_get_recurrence_for_derivative(self, deriv, in_terms_of):
        deriv = np.array(deriv, dtype=int)

        for dim in np.where(2 <= deriv)[0]:
            # Check if we can reduce this dimension in terms of the other
            # dimensions.

            reduced_deriv = deriv.copy()
            reduced_deriv[dim] -= 2
            coeffs = {}

            for other_dim in range(self.dim):
                if other_dim == dim:
                    continue
                needed_deriv = reduced_deriv.copy()
                needed_deriv[other_dim] += 2
                needed_deriv = tuple(needed_deriv)

                if needed_deriv not in in_terms_of:
                    break

                coeffs[needed_deriv] = -1
            else:
                k = sym.Symbol(self.helmholtz_k_name)
                coeffs[tuple(reduced_deriv)] = -k * k
                return coeffs
Exemple #5
0
    def get_loopy_instructions(self):
        from sumpy.symbolic import make_sym_vector
        avec = make_sym_vector("a", self.dim)

        import sumpy.symbolic as sp
        rscale = sp.Symbol("rscale")

        from sumpy.assignment_collection import SymbolicAssignmentCollection
        sac = SymbolicAssignmentCollection()

        coeff_names = [
                sac.assign_unique("coeff%d" % i, coeff_i)
                for i, coeff_i in enumerate(
                    self.expansion.coefficients_from_source(avec, None, rscale))]

        sac.run_global_cse()

        from sumpy.codegen import to_loopy_insns
        return to_loopy_insns(
                six.iteritems(sac.assignments),
                vector_names=set(["a"]),
                pymbolic_expr_maps=[self.expansion.get_code_transformer()],
                retain_names=coeff_names,
                complex_dtype=np.complex128  # FIXME
                )
Exemple #6
0
    def get_loopy_instructions(self):
        from sumpy.symbolic import make_sym_vector
        avec = make_sym_vector("a", self.dim)

        import sumpy.symbolic as sp
        rscale = sp.Symbol("rscale")

        from sumpy.assignment_collection import SymbolicAssignmentCollection
        sac = SymbolicAssignmentCollection()

        coeff_names = []
        for knl_idx, kernel in enumerate(self.kernels):
            for i, coeff_i in enumerate(
                    self.expansion.coefficients_from_source(
                        kernel, avec, None, rscale, sac)):
                sac.add_assignment(f"coeff{i}_{knl_idx}", coeff_i)
                coeff_names.append(f"coeff{i}_{knl_idx}")

        sac.run_global_cse()

        code_transformers = [self.expansion.get_code_transformer()] \
            + [kernel.get_code_transformer() for kernel in self.kernels]

        from sumpy.codegen import to_loopy_insns
        return to_loopy_insns(
            sac.assignments.items(),
            vector_names={"a"},
            pymbolic_expr_maps=code_transformers,
            retain_names=coeff_names,
            complex_dtype=np.complex128  # FIXME
        )
Exemple #7
0
    def track_m2l_op_count(self, param):
        knl = self.knl(param.dim)
        m_expn = self.mpole_expn_class(knl, order=param.order)
        l_expn = self.local_expn_class(knl, order=param.order)

        src_coeff_exprs = [
            sym.Symbol("src_coeff%d" % i) for i in range(len(m_expn))
        ]
        dvec = sym.make_sym_vector("d", knl.dim)
        src_rscale = sym.Symbol("src_rscale")
        tgt_rscale = sym.Symbol("tgt_rscale")
        result = l_expn.translate_from(m_expn, src_coeff_exprs, src_rscale,
                                       dvec, tgt_rscale)
        sac = SymbolicAssignmentCollection()
        for i, expr in enumerate(result):
            sac.assign_unique("coeff%d" % i, expr)
        sac.run_global_cse()
        insns = to_loopy_insns(six.iteritems(sac.assignments))
        counter = pymbolic.mapper.flop_counter.CSEAwareFlopCounter()

        return sum([counter.rec(insn.expression) + 1 for insn in insns])
    def __call__(self, base="expr"):
        base = self._normalize(base)
        count = self.base_to_count[base]

        def make_id_str(base, count):
            return "{base}{suffix}".format(base=base,
                                           suffix="" if count == 0 else "_" +
                                           str(count - 1))

        id_str = make_id_str(base, count)
        while id_str in self.taken_symbols:
            count += 1
            id_str = make_id_str(base, count)

        self.base_to_count[base] = count + 1

        return sym.Symbol(id_str)
Exemple #9
0
    def coefficients_from_source(self, avec, bvec, rscale):
        # no point in heeding rscale here--just ignore it
        if bvec is None:
            raise RuntimeError(
                "cannot use line-Taylor expansions in a setting "
                "where the center-target vector is not known at coefficient "
                "formation")

        tau = sym.Symbol("tau")

        avec_line = avec + tau * bvec

        line_kernel = self.kernel.get_expression(avec_line)

        from sumpy.symbolic import USE_SYMENGINE

        if USE_SYMENGINE:
            from sumpy.tools import MiDerivativeTaker, my_syntactic_subs
            deriv_taker = MiDerivativeTaker(line_kernel, (tau, ))

            return [
                my_syntactic_subs(
                    self.kernel.postprocess_at_target(
                        self.kernel.postprocess_at_source(
                            deriv_taker.diff(i), avec), bvec), {tau: 0})
                for i in self.get_coefficient_identifiers()
            ]
        else:
            # Workaround for sympy. The automatic distribution after
            # single-variable diff makes the expressions very large
            # (https://github.com/sympy/sympy/issues/4596), so avoid doing
            # single variable diff.
            #
            # See also https://gitlab.tiker.net/inducer/pytential/merge_requests/12

            return [
                self.kernel.postprocess_at_target(
                    self.kernel.postprocess_at_source(
                        line_kernel.diff("tau", i), avec),
                    bvec).subs("tau", 0)
                for i in self.get_coefficient_identifiers()
            ]
Exemple #10
0
 def get_pde_as_diff_op(self, **kwargs):
     w = make_identity_diff_op(self.dim)
     k = sym.Symbol(self.helmholtz_k_name)
     return (laplacian(w) + k**2 * w)
Exemple #11
0
 def save_intermediate(expr):
     if sac is None:
         return expr
     return sym.Symbol(sac.assign_unique("compress_temp", expr))
Exemple #12
0
 def save_intermediate(expr):
     if sac is None:
         return expr
     return sym.Symbol(sac.assign_unique("projection_temp", expr))
Exemple #13
0
 def get_bessel_arg_scaling(self):
     return sym.I * sym.Symbol(self.kernel.get_base_kernel().yukawa_lambda_name)
Exemple #14
0
 def get_bessel_arg_scaling(self):
     return sym.Symbol(self.kernel.get_base_kernel().helmholtz_k_name)
Exemple #15
0
class LinearRecurrenceBasedDerivativeWrangler(DerivativeWrangler):
    _rscale_symbol = sp.Symbol("_sumpy_rscale_placeholder")

    def get_coefficient_identifiers(self):
        return self.stored_identifiers

    def get_full_kernel_derivatives_from_stored(self,
                                                stored_kernel_derivatives,
                                                rscale):
        coeff_matrix = self.get_coefficient_matrix(rscale)
        return _spmv(coeff_matrix,
                     stored_kernel_derivatives,
                     sparse_vectors=False)

    def get_stored_mpole_coefficients_from_full(self, full_mpole_coefficients,
                                                rscale):
        # = M^T x, where M = coeff matrix

        coeff_matrix = self.get_coefficient_matrix(rscale)
        result = [0] * len(self.stored_identifiers)
        for row, coeff in enumerate(full_mpole_coefficients):
            for col, val in coeff_matrix[row]:
                result[col] += coeff * val
        return result

    @property
    def stored_identifiers(self):
        stored_identifiers, coeff_matrix = self._get_stored_ids_and_coeff_mat()
        return stored_identifiers

    @memoize_method
    def get_coefficient_matrix(self, rscale):
        """
        Return a matrix that expresses every derivative in terms of a
        set of "stored" derivatives.

        For example, for the recurrence

            u_xx + u_yy + u_zz = 0

        the coefficient matrix features the following entries:

              ... u_xx u_yy ... <= cols = only stored derivatives
             ==================
         ...| ...  ...  ... ...
            |
        u_zz| ...  -1   -1  ...

           ^ rows = one for every derivative
        """
        stored_identifiers, coeff_matrix = self._get_stored_ids_and_coeff_mat()

        # substitute actual rscale for internal placeholder
        return defaultdict(
            lambda: [],
            ((irow, [(icol, coeff.xreplace({self._rscale_symbol: rscale})
                      if isinstance(coeff, sp.Basic) else coeff)
                     for icol, coeff in row])
             for irow, row in six.iteritems(coeff_matrix)))

    @memoize_method
    def _get_stored_ids_and_coeff_mat(self):
        stored_identifiers = []
        identifiers_so_far = {}

        import time
        start_time = time.time()
        logger.debug("computing recurrence for Taylor coefficients: start")

        # Sparse matrix, indexed by row
        coeff_matrix_transpose = defaultdict(lambda: [])

        # Build up the matrix transpose by row.
        from six import iteritems
        for i, identifier in enumerate(
                self.get_full_coefficient_identifiers()):
            expr = self.try_get_recurrence_for_derivative(
                identifier, identifiers_so_far, rscale=self._rscale_symbol)

            if expr is None:
                # Identifier should be stored
                coeff_matrix_transpose[len(stored_identifiers)] = [(i, 1)]
                stored_identifiers.append(identifier)
            else:
                expr = dict((identifiers_so_far[ident], val)
                            for ident, val in iteritems(expr))
                result = _spmv(coeff_matrix_transpose,
                               expr,
                               sparse_vectors=True)
                for j, item in iteritems(result):
                    coeff_matrix_transpose[j].append((i, item))

            identifiers_so_far[identifier] = i

        stored_identifiers = stored_identifiers

        coeff_matrix = defaultdict(lambda: [])
        for i, row in iteritems(coeff_matrix_transpose):
            for j, val in row:
                coeff_matrix[j].append((i, val))

        logger.debug("computing recurrence for Taylor coefficients: "
                     "done after {dur:.2f} seconds".format(dur=time.time() -
                                                           start_time))

        logger.debug(
            "number of Taylor coefficients was reduced from {orig} to {red}".
            format(orig=len(self.get_full_coefficient_identifiers()),
                   red=len(stored_identifiers)))

        return stored_identifiers, coeff_matrix

    def try_get_recurrence_for_derivative(self, deriv, in_terms_of, rscale):
        """
        :arg deriv: a tuple of integers identifying a derivative for which
            a recurrence is sought
        :arg in_terms_of: a container supporting efficient containment testing
            indicating availability of derivatives for use in recurrences
        """

        raise NotImplementedError

    def get_derivative_taker(self, expr, var_list):
        from sumpy.tools import LinearRecurrenceBasedMiDerivativeTaker
        return LinearRecurrenceBasedMiDerivativeTaker(expr, var_list, self)