def interval_approximate_nd(f, a, b, degs): """Finds the chebyshev approximation of an n-dimensional function on an interval. Parameters ---------- f : function from R^n -> R The function to interpolate. a : numpy array The lower bound on the interval. b : numpy array The upper bound on the interval. deg : numpy array The degree of the interpolation in each dimension. Returns ------- coeffs : numpy array The coefficient of the chebyshev interpolating polynomial. """ if len(a) != len(b): raise ValueError("Interval dimensions must be the same!") dim = len(a) def get_cheb_spot(k, n): return np.cos(np.pi * k / n) values = np.zeros(2 * degs) cheb_spots = list() for spot, val in np.ndenumerate(values): cheb_spots.append( transform([get_cheb_spot(spot[i], degs[i]) for i in range(dim)], a, b)) vals = f(cheb_spots) i = 0 for spot, val in np.ndenumerate(values): values[spot] = vals[i] i += 1 coeffs = np.real(fftn(values / np.product(degs))) for i in range(dim): idx0 = [slice(None)] * (dim) idx0[i] = 0 idx00 = [slice(None)] * (dim) idx00[i] = degs[i] coeffs[idx0] = coeffs[idx0] / 2 coeffs[idx00] = coeffs[idx00] / 2 slices = list() for i in range(dim): slices.append(slice(0, degs[i] + 1)) return coeffs[slices]
def proj_approximate_nd(f,transform): """Finds the chebyshev approximation of an n-dimensional function on the affine transformation of hypercube. Parameters ---------- f : function from R^n -> R The function to project by interpolating. transform : function from R^(n-1) -> R^n The affine function mapping the hypercube to the desired space. Returns ------- coeffs : numpy array The coefficient of the chebyshev interpolating polynomial. """ dim = f.dim proj_dim = dim-1 deg = f.degree degs = np.array([deg]*proj_dim) # assert hasattr(f,"evaluate_grid") # dang, we don't get to use evaluate_grid here cheb_values = np.cos(np.arange(deg+1)*np.pi/deg) cheb_grids = np.meshgrid(*([cheb_values]*proj_dim), indexing='ij') flatten = lambda x: x.flatten() cheb_points = transform(np.column_stack(map(flatten, cheb_grids))) values_block = f(cheb_points).reshape(*([deg+1]*proj_dim)) values = chebyshev_block_copy(values_block) coeffs = np.real(fftn(values/np.product(degs))) for i in range(proj_dim): #construct slices for the first and degs[i] entry in each dimension idx0 = [slice(None)] * proj_dim idx0[i] = 0 idx_deg = [slice(None)] * proj_dim idx_deg[i] = degs[i] #halve the coefficients in each slice coeffs[tuple(idx0)] /= 2 coeffs[tuple(idx_deg)] /= 2 slices = [] for i in range(proj_dim): slices.append(slice(0,degs[i]+1)) return trim_coeff(coeffs[tuple(slices)])
def reference_fftn(self, a, axes): return np_fft.fftn(a, axes=axes)
def interval_approximate_nd(f, a, b, degs): """Finds the chebyshev approximation of an n-dimensional function on an interval. Parameters ---------- f : function from R^n -> R The function to interpolate. a : numpy array The lower bound on the interval. b : numpy array The upper bound on the interval. deg : numpy array The degree of the interpolation in each dimension. Returns ------- coeffs : numpy array The coefficient of the chebyshev interpolating polynomial. """ if len(a) != len(b): raise ValueError("Interval dimensions must be the same!") dim = len(a) deg = degs[0] if hasattr(f, "evaluate_grid"): #for polynomials, we can quickly evaluate all points in a grid #xyz does not contain points, but the nth column of xyz has the values needed #along the nth axis. The direct product of these values procuces the grid cheb_values = np.cos(np.arange(deg + 1) * np.pi / deg) xyz = transform(np.column_stack([cheb_values] * dim), a, b) values_block = f.evaluate_grid(xyz) else: #if function f has no "evaluate_grid" method, #we evaluate each point individually cheb_values = np.cos(np.arange(deg + 1) * np.pi / deg) cheb_grids = np.meshgrid(*([cheb_values] * dim), indexing='ij') flatten = lambda x: x.flatten() cheb_points = transform(np.column_stack(map(flatten, cheb_grids)), a, b) values_block = f(cheb_points).reshape(*([deg + 1] * dim)) values = chebyshev_block_copy(values_block) coeffs = np.real(fftn(values / np.product(degs))) for i in range(dim): #construct slices for the first and degs[i] entry in each dimension idx0 = [slice(None)] * dim idx0[i] = 0 idx_deg = [slice(None)] * dim idx_deg[i] = degs[i] #halve the coefficients in each slice coeffs[idx0] /= 2 coeffs[idx_deg] /= 2 slices = [] for i in range(dim): slices.append(slice(0, degs[i] + 1)) return coeffs[slices]