From 3ee9624c7b90b532708fb11ef08af1f361cfc47c Mon Sep 17 00:00:00 2001 From: Isuru Fernando <isuruf@gmail.com> Date: Tue, 25 Jun 2019 17:19:31 +0200 Subject: [PATCH] Get rid of M = N * N_top^-1 and use algorithm in new proof --- sumpy/expansion/__init__.py | 93 ++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 53 deletions(-) diff --git a/sumpy/expansion/__init__.py b/sumpy/expansion/__init__.py index 60f6eb5b..5e925f44 100644 --- a/sumpy/expansion/__init__.py +++ b/sumpy/expansion/__init__.py @@ -24,7 +24,6 @@ THE SOFTWARE. from six.moves import range import six -import numpy as np import logging from pytools import memoize_method import sumpy.symbolic as sym @@ -393,73 +392,61 @@ class LinearPDEBasedExpansionTermsWrangler(ExpansionTermsWrangler): @memoize_method def get_stored_ids_and_coeff_mat(self): from six import iteritems - from sumpy.tools import nullspace, solve_symbolic from pytools import ProcessLogger plog = ProcessLogger(logger, "compute PDE for Taylor coefficients") pdes, iexpr, nexpr = self.get_pdes() - pde_mat = [] mis = self.get_full_coefficient_identifiers() coeff_ident_enumerate_dict = dict((tuple(mi), i) for (i, mi) in enumerate(mis)) - offset = len(mis) - - for mi in mis: - for pde_dict in pdes.eqs: - eq = [0]*(len(mis)*nexpr) - for ident, coeff in iteritems(pde_dict): - c = tuple(add_mi(ident.mi, mi)) - if c not in coeff_ident_enumerate_dict: - break - eq[offset*ident.iexpr + coeff_ident_enumerate_dict[c]] = coeff - else: - pde_mat.append(eq) - - if len(pde_mat) > 0: - r""" - Find a matrix :math:`s` such that :math:`K = S^T K_{[r]}` - where :math:`r` is the indices of the reduced coefficients and - :math:`K` is a column vector of coefficients. Let :math:`P` be the - PDE matrix, i.e. the matrix obtained by applying the PDE - as an identity to each of the Taylor coefficients. - (Realize that those, as functions of space, each still satisfy the PDE.) - As a result, if :math:`\mathbf\alpha` is a vector of Taylor coefficients, - one would expect :math:`P\mathbf\alpha = \mathbf 0`. - Further, let :math:`N` be the nullspace of :math:`P`. - Then, :math:`S^T = N * N_{[r, :]}^{-1}` which implies, - :math:`S = N_{[r, :]}^{-T} N^T = N_{[r, :]}^{-T} N^T`. - """ - n = nullspace(pde_mat) - # Move the rows corresponding to this expression to the front - rearrange = list(range(offset*iexpr, offset*(iexpr+1))) - for i in range(nexpr*offset): - if i < offset*iexpr or i >= offset*(iexpr+1): - rearrange.append(i) - n = n[rearrange, :] + pde = self.get_single_pde() + assert len(pde.eqs) == 1 + pde_dict = pde.eqs[0] + max_mi_idx = max(coeff_ident_enumerate_dict[ident.mi] for + ident in pde_dict.keys()) + max_mi = mis[max_mi_idx] + max_mi_coeff = pde_dict[CoeffIdentifier(max_mi, 0)] + max_mi_mult = -1/sym.sympify(max_mi_coeff) - # Get the indices of the reduced coefficients - idx_all_exprs = self.get_reduced_coeffs(n) + def is_stored(mi): + """ + A multi_index mi is not stored if mi >= max_mi + """ + return any(mi[d] < max_mi[d] for d in range(self.dim)) - s = solve_symbolic(n.T[:, idx_all_exprs], n.T) - # Filter out coefficients belonging to this expression - indices = list(filter(lambda x: x < offset, idx_all_exprs)) - s = s[:len(indices), :offset] + stored_identifiers = [mi for mi in mis if is_stored(mi)] + stored_ident_enumerate_dict = dict((tuple(mi), i) for + (i, mi) in enumerate(stored_identifiers)) - stored_identifiers = [mis[i] for i in indices] - else: - s = np.eye(len(mis)) - stored_identifiers = mis - idx_all_exprs = list(range(len(mis))) + coeff_matrix_dict = defaultdict(lambda: defaultdict(lambda: 0)) + reconstruct_matrix = defaultdict(list) + for i, mi in enumerate(mis): + if is_stored(mi): + coeff_matrix_dict[i][stored_ident_enumerate_dict[mi]] = 1 + continue + diff = [mi[d] - max_mi[d] for d in range(self.dim)] + for other_mi, coeff in iteritems(pde_dict): + j = coeff_ident_enumerate_dict[add_mi(other_mi.mi, diff)] + if i == j: + continue + # PDE might not have max_mi_coeff = -1, divide by -max_mi_coeff + # to get a relation of the form, u_zz = - u_xx - u_yy for Laplace 3D. + reconstruct_matrix[i].append((j, coeff*max_mi_mult)) + # j can be a stored or a non-stored multi-index + # Look at the coeff_matrix of j to get the j as a linear combination + # of stored coefficients. + for dep, other_coeff in iteritems(coeff_matrix_dict[j]): + coeff_matrix_dict[i][dep] += other_coeff*coeff*max_mi_mult # coeff_matrix is a dictionary of lists. Each key in the dictionary # is a row number and the values are pairs of column number and value. coeff_matrix = defaultdict(list) - for i in range(s.shape[0]): - for j in range(s.shape[1]): - if s[i, j] != 0: - coeff_matrix[j].append((i, s[i, j])) + for row, deps in iteritems(coeff_matrix_dict): + for col, val in iteritems(deps): + if val != 0: + coeff_matrix[row].append((col, val)) plog.done() @@ -467,7 +454,7 @@ class LinearPDEBasedExpansionTermsWrangler(ExpansionTermsWrangler): .format(orig=len(self.get_full_coefficient_identifiers()), red=len(stored_identifiers))) - return stored_identifiers, coeff_matrix, pde_mat + return stored_identifiers, coeff_matrix, None def get_pdes(self): r""" -- GitLab