def test_1d_make_interp(ndspline): for k in range(4): N = np.random.randint(k + 1, 35) sample_x = get_grid_data(N).reshape(-1) sample_y = ndspline(sample_x) nspl = ndsplines.make_interp_spline(sample_x, sample_y, k) ispl = interpolate.make_interp_spline(sample_x, sample_y, k) assert_allclose(nspl.coefficients.reshape(-1), ispl.c.reshape(-1))
def test_nd_make_lsq(ndspline): sample_x = get_grid_data( *[t.size - k - 1 for t, k in zip(ndspline.knots, ndspline.degrees)]) sample_y = ndspline(sample_x) k = 3 nspl = ndsplines.make_interp_spline(sample_x, sample_y, k) knots_to_reproduce = un_knot_a_knot(nspl.knots, nspl.degrees) knot_sample_x = np.stack(np.meshgrid(*knots_to_reproduce, indexing='ij'), axis=-1) knot_sample_y = ndspline(knot_sample_x) nspl = ndsplines.make_interp_spline(knot_sample_x, knot_sample_y, k) sample_x = np.stack(np.meshgrid(*[ np.linspace(0, 1, int(1.5 * nspl.xshape[i])) for i in range(nspl.xdim) ], indexing='ij'), axis=-1).reshape((-1, nspl.xdim)) sample_y = nspl(sample_x) nlsq = ndsplines.make_lsq_spline(sample_x, sample_y, nspl.knots, nspl.degrees) assert_allclose(nlsq.coefficients, nspl.coefficients, rtol=1E-4) sample_y_orig = sample_y signal_rms = (sample_y**2).sum(axis=0) / sample_x.size N_samples = 4 set_snrs = np.empty(N_samples) eval_snrs = np.empty(N_samples) for snr_exp in range(N_samples): snr_ratio = 10**(0 * nspl.xdim + snr_exp) sample_y = sample_y_orig + signal_rms[ None, :] / snr_ratio * np.random.random(sample_y.shape) nlsq = ndsplines.make_lsq_spline(sample_x, sample_y, nspl.knots, nspl.degrees) eval_snrs[snr_exp] = np.max( np.abs(nlsq.coefficients - nspl.coefficients) / nspl.coefficients) set_snrs[snr_exp] = snr_ratio assert (np.diff(np.log10(eval_snrs)).mean() < np.diff(np.log10(set_snrs)).mean() / 2)
def test_make_interp_nn(): """Verify nearest neighbor special case.""" dx = 0.1 x = np.arange(0, 1, dx) y = np.sin(2 * np.pi * x) spl = ndsplines.make_interp_spline(x, y, degrees=0) # samples at offsets less than dx/2 will be same as original values xx = x[:-1] + dx / 4 assert_allclose(spl(xx), spl(x[:-1]))
def test_make_interp_x_mesh(n_vals): """Input x arrays of varying dimensionality.""" xarrays = [np.linspace(0, 1, n) for n in n_vals] x = np.stack(np.meshgrid(*xarrays, indexing='ij'), axis=-1) y = np.random.rand(*n_vals) spl = ndsplines.make_interp_spline(x, y) assert spl.xdim == len(n_vals) xsamp = np.random.randn(10, len(n_vals)) assert spl(xsamp).shape == (10, )
def test_make_interp_nd_y(ydim): """Multi-dimensional y.""" x = np.linspace(0, 1, 10) y = np.random.rand(10, ydim) spl = ndsplines.make_interp_spline(x, y) assert spl.xdim == 1 assert spl.ydim == ydim samps = spl(np.random.rand(20)) assert samps.shape == (20, ydim)
def test_nd_make_interp(ndspline): sample_x = get_grid_data( *[t.size - k - 1 for t, k in zip(ndspline.knots, ndspline.degrees)]) sample_y = ndspline(sample_x) k = 3 # does it interpolate? # TODO: figure out how to loop degrees nspl = ndsplines.make_interp_spline(sample_x, sample_y, k) assert_allclose(sample_y, nspl(sample_x)) # can make_interp_spline recreate a spline with known knots? (same spline space) knots_to_reproduce = un_knot_a_knot(nspl.knots, nspl.degrees) knot_sample_x = np.stack(np.meshgrid(*knots_to_reproduce, indexing='ij'), axis=-1) knot_sample_y = nspl(knot_sample_x) nspl2 = ndsplines.make_interp_spline(knot_sample_x, knot_sample_y, nspl.degrees) assert_equal_splines(nspl, nspl2) # can you use a tidy dataformat? tidy_x = knot_sample_x.reshape((-1, nspl.xdim)) tidy_y = knot_sample_y.reshape((-1, nspl.ydim)) tidy_array = np.concatenate((tidy_x, tidy_y), axis=1) x_sel = np.arange(nspl.xdim) y_sel = np.arange(nspl.ydim) + nspl.xdim tidy_df = pd.DataFrame( tidy_array, columns=['column %d' % i for i in range(tidy_array.shape[1])]) nspl3 = ndsplines.make_interp_spline_from_tidy(tidy_array, x_sel, y_sel) assert_equal_splines(nspl, nspl3) tidy_df_x_col = tidy_df.columns[x_sel] tidy_df_y_col = tidy_df.columns[y_sel] nspl4 = ndsplines.make_interp_spline_from_tidy(tidy_df, tidy_df_x_col, tidy_df_y_col) assert_equal_splines(nspl, nspl4)
def test_make_interp_x_vectors(n_vals): """Check that a list of vectors is accepted for x. y input in this case should have shape (n_ndim1, n_ndim2, ...) as if it were sampled on the grid. """ x = [np.linspace(0, 1, n) for n in n_vals] xgrid = np.stack(np.meshgrid(*x, indexing='ij'), axis=-1) y = np.random.rand(*n_vals) spl = ndsplines.make_interp_spline(x, y) assert spl.xdim == len(n_vals) assert spl.ydim == 1 assert_allclose(spl(xgrid), y)
def test_2d_make_interp(ndspline): for kx in range(1, 4): nx = np.random.randint(4, 35) for ky in range(1, 4): ny = np.random.randint(4, 35) sample_x = get_grid_data(nx, ny).squeeze() sample_y = ndspline(sample_x).squeeze() nspl = ndsplines.make_interp_spline(sample_x, sample_y, [kx, ky]) ispl = interpolate.RectBivariateSpline(sample_x[:, 0, 0], sample_x[0, :, 1], sample_y, kx=kx, ky=ky) assert_allclose(nspl.coefficients.reshape(-1), ispl.get_coeffs().reshape(-1))
n_iter=n_iter) t_ndspl = 10e3 * timeit(ndsplines.make_interp_spline, x=x.copy(), y=y, n_iter=n_iter) t_scipy_build[:, i] = np.mean(t_scipy), np.std(t_scipy) t_ndspl_build[:, i] = np.mean(t_ndspl), np.std(t_ndspl) # spline query timing x, y = gen_xy(7) xx_sizes = np.logspace(0, 3, 10, dtype=int) t_scipy_call = np.empty((2, xx_sizes.size)) t_ndspl_npy_call = np.empty((2, xx_sizes.size)) t_ndspl_pyx_call = np.empty((2, xx_sizes.size)) for i, size in enumerate(xx_sizes): xx = gen_xx(size) spl_scipy = interpolate.make_interp_spline(x.copy(), y) spl_ndspl = ndsplines.make_interp_spline(x.copy(), y) spl_ndspl.allocate_workspace_arrays(size) t_scipy = 10e3 * timeit(spl_scipy, x=xx.copy(), n_iter=n_iter) ndsplines.set_impl('cython') t_ndspl_pyx = 10e3 * timeit(spl_ndspl, x=xx.copy(), n_iter=n_iter) ndsplines.set_impl('numpy') t_ndspl_npy = 10e3 * timeit(spl_ndspl, x=xx.copy(), n_iter=n_iter) t_scipy_call[:, i] = np.mean(t_scipy), np.std(t_scipy) t_ndspl_npy_call[:, i] = np.mean(t_ndspl_npy), np.std(t_ndspl_npy) t_ndspl_pyx_call[:, i] = np.mean(t_ndspl_pyx), np.std(t_ndspl_pyx) # plot results fig, axes = plt.subplots(nrows=2) axes[0].errorbar(x_sizes, t_scipy_build[0], capsize=3, yerr=t_scipy_build[1], label='scipy')
def test_make_interp_invalid_y(): """Bad input raises ValueError.""" with pytest.raises(ValueError): ndsplines.make_interp_spline(np.arange(10), np.zeros((9, 10, 10, 10)))
def test_make_interp_invalid_x(): """Bad input raises ValueError.""" with pytest.raises(ValueError): ndsplines.make_interp_spline('str', np.arange(3))
def test_make_interp_scipy_compat(): """Basic test of compatibility with scipy.interpolate API.""" x = np.linspace(0, 1, 10) y = np.sin(x) spl = ndsplines.make_interp_spline(x, y) spl(np.linspace(0, 1, 100))
der_Bspline = test_Bspline.derivative() axes[1].plot(xx, der_Bspline(xx.copy()), '--', lw=3.0, label='BSpline') antider_Bspline = test_Bspline.antiderivative() axes[-1].plot(xx, antider_Bspline(xx.copy()), '--', lw=3.0, label='BSpline') for ax in axes: ax.set_prop_cycle(None) test_NDBspline = ndsplines.make_interp_spline(x, fvals, degrees=degree) NDsplinef = test_NDBspline(xx.copy()) axes[0].plot(xx, NDsplinef, label='ndspline') if degree > 0: der_NDspline = test_NDBspline.derivative(0) axes[1].plot(xx, der_NDspline(xx.copy()), label='ndspline') antider_NDspline = test_NDBspline.antiderivative(0) axes[-1].plot(xx, antider_NDspline(xx.copy()), label='ndspline') axes[0].plot(xx, truef, 'k--', label="True " + func.__name__) axes[0].plot(x, fvals, 'ko') plt.suptitle('k=%d' % degree) axes[0].legend(loc='best') plt.show()
def test_make_interp_1d_y(): """Check that output is squeezed ndim==1 for 1D y.""" x = np.linspace(0, 1, 10) y = np.sin(x) spl = ndsplines.make_interp_spline(x, y) assert spl(np.random.rand(20)).shape == (20, )
def __init__(self, grid_input: List[List[float]], data_input: np.array, lut_interp_types: List[str], version='nds-1'): self.lut_interp_types = lut_interp_types self.single_point_data = None # Lists and arrays are mutable, so copy first grid = grid_input.copy() data = data_input.copy() # Check if we are using a single grid point. If so, store the grid input. if np.prod(list(map(len, grid))) == 1: self.single_point_data = data # expand grid dimensionality as needed [radian_locations] = np.where(self.lut_interp_types == 'r') [degree_locations] = np.where(self.lut_interp_types == 'd') angle_locations = np.hstack([radian_locations, degree_locations]) angle_types = np.hstack([ self.lut_interp_types[radian_locations], self.lut_interp_types[degree_locations] ]) for _angle_loc in range(len(angle_locations)): angle_loc = angle_locations[_angle_loc] # get original grid at given location original_grid_subset = np.array(grid[angle_loc]) # convert for angular coordinates if (angle_types[_angle_loc] == 'r'): grid_subset_cosin = np.cos(original_grid_subset) grid_subset_sin = np.sin(original_grid_subset) elif (angle_types[_angle_loc] == 'd'): grid_subset_cosin = np.cos(np.deg2rad(original_grid_subset)) grid_subset_sin = np.sin(np.deg2rad(original_grid_subset)) # handle the fact that the grid may no longer be in order grid_subset_cosin_order = np.argsort(grid_subset_cosin) grid_subset_sin_order = np.argsort(grid_subset_sin) # convert current grid location, and add a second grid[angle_loc] = grid_subset_cosin[grid_subset_cosin_order] grid.insert(angle_loc + 1, grid_subset_sin[grid_subset_sin_order]) # now copy the data to be interpolated through the extra dimension, # at the specific angle_loc axes. We'll use broadcast_to to do # this, but we need to do it on the last dimension. So start by # temporarily moving the target axes there, then broadcasting data = np.swapaxes(data, -1, angle_loc) data_dim = list(np.shape(data)) data_dim.append(data_dim[-1]) data = data[..., np.newaxis] * np.ones(data_dim) # Now we need to actually copy the data between the first two axes, # as broadcast_to doesn't do this for ind in range(data.shape[-1]): data[..., ind] = data[..., :, ind] # Now re-order the cosin dimension data = data[..., grid_subset_cosin_order, :] # Now re-order the sin dimension data = data[..., grid_subset_sin_order] # now re-arrange the axes so they're in the right order again, dst_axes = np.arange(len(data.shape) - 2).tolist() dst_axes.insert(angle_loc, len(data.shape) - 2) dst_axes.insert(angle_loc + 1, len(data.shape) - 1) dst_axes.remove(angle_loc) dst_axes.append(angle_loc) data = np.ascontiguousarray(np.transpose(data, axes=dst_axes)) # update the rest of the angle locations angle_locations += 1 self.n = data.shape[-1] if version == 'rg': grid_aug = grid + [np.arange(data.shape[-1])] self.itp = RegularGridInterpolator(grid_aug, data, bounds_error=False, fill_value=None) elif version[:3] == 'nds': degrees = int(version[4:]) grid_aug = grid + [np.arange(data.shape[-1]).tolist()] grid_arr = np.stack(np.meshgrid(*grid_aug, indexing='ij'), axis=-1) self.itp = ndsplines.make_interp_spline(grid_arr, data, degrees=degrees) else: raise_str = f'Unknown interpoloator version {version}' raise ArgumentError(raise_str)
def process_xml(self, xml_parsed_data): for idx, child in enumerate(xml_parsed_data.getchildren()): if isinstance(child.tag, str): if isTag(child, '/DAVEML}variableDef'): if child.attrib['varID'] in self.symbol_table: warnings.warn("%s variable already in symbol table!" % child.attrib['varID']) self.symbol_table[child.attrib['varID']] = sp.Symbol(child.attrib['varID']) hasLimits = ('minValue' in child.attrib) or ('maxValue' in child.attrib) isInput = False isOutput = False isAssigned = False for varChild in child.getchildren(): if isTag(varChild, '/DAVEML}isInput'): isInput = True if isTag(varChild, '/DAVEML}isOutput'): isOutput = True if isTag(varChild, '/DAVEML}calculation'): mathTags = filterTags(varChild.getchildren()) if len(mathTags) != 1: raise ValueError("A calculation tag should hold only one non-comment tag") if not isTag(mathTags[0], '/MathML}math'): raise ValueError("A calculation tag should hold only one math tag") for mathChild in mathTags[0].getchildren(): # iterate over children of math tag processed_apply = False if isinstance(mathChild, etree._Comment): pass elif isTag(mathChild, '/MathML}apply'): if processed_apply: raise ValueError("Trying to apply multiple times within a Math tag") processed_apply = True expr = self.xml_to_sympy_expr( mathChild ) self.check_dependencies(expr.atoms(sp.Symbol)) self.extra_assignments[self.symbol_table[child.attrib['varID']]] = expr isAssigned = True else: raise ValueError("Unexpected tag under calculation.math %s" % mathChild) if (('initialValue' in child.attrib.keys()) and not isInput): # we have no way of knowing if this is a constant or an internal variable with "initial value" -- not sure why this needs that! self.constants[self.symbol_table[child.attrib['varID']]] = float(child.attrib['initialValue']) if isInput: self.input_vars.append(self.symbol_table[child.attrib['varID']]) if isOutput: self.output_vars.append(self.symbol_table[child.attrib['varID']]) if not isAssigned: # declared with default value (may be overwritten) OR unspecified self.extra_assignments[self.symbol_table[child.attrib['varID']]] = None elif hasLimits: # isAssigned self.extra_assignments[self.symbol_table[child.attrib['varID']]] = sp.Function('numpy.clip')( self.extra_assignments[self.symbol_table[child.attrib['varID']]], float(child.attrib.get('minValue', -np.inf)), float(child.attrib.get('maxValue', np.inf)) ) elif isTag(child, '/DAVEML}fileHeader'): print("Skipping header") elif isTag(child, '/DAVEML}breakpointDef'): description, bpvals = child.getchildren() self.breakpoints[child.attrib['bpID']] = np.array([float(num) for num in bpvals.text.split(',')]) elif isTag(child, '/DAVEML}function') or isTag(child, '/DAVEML}griddedTableDef'): # function # independentVarRef # dependentVarRef # functionDefn # griddedTableDef gtID # breakpoint_refs # datatable input_vars = [] # DaveML assumes only 1 output for function from_function = isTag(child, '/DAVEML}function') from_griddedTable = isTag(child, '/DAVEML}griddedTableDef') make_spline = True for functionChild in child.getchildren(): if isinstance(functionChild, etree._Comment): pass elif from_function and isTag(functionChild, '/DAVEML}independentVarRef'): input_vars.append(self.symbol_table[functionChild.attrib['varID']]) elif from_function and isTag(functionChild, '/DAVEML}dependentVarRef'): output_var = self.symbol_table[functionChild.attrib['varID']] elif ((from_function and isTag(functionChild, '/DAVEML}functionDefn')) or from_griddedTable): if from_function: functionDefnChildren = filterTags(functionChild.getchildren()) if len(functionDefnChildren) != 1: raise ValueError("A functionDefn tag should hold only one non-comment tag") if isTag(functionDefnChildren[0], '/DAVEML}griddedTableDef'): griddedTableDef = functionDefnChildren[0] elif isTag(functionDefnChildren[0], '/DAVEML}griddedTableRef'): spline = self.extra_tables[functionDefnChildren[0].attrib['gtID']] make_spline = False else: raise ValueError("A functionDefn tag should hold only one griddedTableDef or griddedTableRef tag") elif from_griddedTable: griddedTableDef = child if make_spline: breakpoint_refs, data_table = None, None for griddedTableDefChild in filterTags(griddedTableDef.getchildren()): if isTag(griddedTableDefChild, '/DAVEML}breakpointRefs'): if breakpoint_refs is None: breakpoint_refs = griddedTableDefChild else: raise ValueError("Too many breakpoint_refs tags") if isTag(griddedTableDefChild, '/DAVEML}dataTable'): if data_table is None: data_table = griddedTableDefChild else: raise ValueError("Too many data_table tags") knots_arrays = [] for breakpoint_ref in breakpoint_refs: knots_arrays.append(self.breakpoints[breakpoint_ref.attrib['bpID']]) data_table = np.array([float(num) for num in delimeter_regex.split(data_table.xpath('string()').strip()) if num is not '']).reshape([knots_array.size for knots_array in knots_arrays]) spline = ndsplines.make_interp_spline(knots_arrays, data_table, degrees=1) if from_griddedTable: self.extra_tables[griddedTableDef.attrib['gtID']] = spline break if from_function: spline_sym_func = sp.symbols(functionChild.attrib['name'], cls=sp.Function)(tuple(input_vars)) spline_sym_func.shape = (1,) self.splines[spline_sym_func] = spline self.check_dependencies(input_vars) # self.extra_assignments[output_var] = spline_sym_func self.extra_assignments[output_var] = spline_sym_func elif isTag(functionChild, '/DAVEML}description') or isTag(functionChild, '/DAVEML}provenance'): pass else: raise ValueError("Unexpected child %s of function %s " % (functionChild.tag, child.tag)) elif isTag(child, '/DAVEML}checkData'): for checkDataTag in filterTags(child.getchildren()): inputs = {} outputs = {} # TODO: defensive checks for tags? -- this is a common pattern, I could definitely refactor # maybe lxml/ElementTree has a way to do it? inputTag = None outputTag = None for checkTag in filterTags(checkDataTag.getchildren()): if isTag(checkTag, '/DAVEML}checkInputs'): if inputTag is not None: raise ValueError("Too many checkInputs tags") inputTag = checkTag elif isTag(checkTag, '/DAVEML}checkOutputs'): if outputTag is not None: raise ValueError("Too many checkOutputs tags") outputTag = checkTag elif isTag(checkTag, '/DAVEML}internalValues'): pass else: raise ValueError("Unsupported tag") for local_dict, global_dict, tag in zip( [inputs, outputs], [self.input_vars, self.output_vars], [inputTag, outputTag]): for signal in tag: # TODO: unit conversion check? Or document assumption of consistent units # to follow the spec, would need more careful handling... https://daveml.org/DTDs/1p7b1/Ref/re40.html signalName = None signalUnits = None signalValue = None signalTol = None for signalChild in filterTags(signal.getchildren()): if isTag(signalChild, '/DAVEML}signalName'): if signalName is not None: raise ValueError("Too many signalName tags") signalName = signalChild elif isTag(signalChild, '/DAVEML}signalID'): raise ValueError("signalID tag unsupported") elif isTag(signalChild, '/DAVEML}signalUnits'): if signalUnits is not None: raise ValueError("Too many signalUnits tags") signalUnits = signalChild elif isTag(signalChild, '/DAVEML}signalValue'): if signalValue is not None: raise ValueError("Too many signalValue tags") signalValue = signalChild elif isTag(signalChild, '/DAVEML}tol'): pass else: raise ValueError("Unsupported tag") # TODO: input/output use "name" here instead of "varID", so to validate the data would require tracking it # aero example preserves order, so we will assume that as well... # TODO: document assumption # if self.symbol_table[signalName.text] not in global_dict: # raise ValueError("Unrecognized variable %s" % signalName.text) local_dict[signalName.text] = float(signalValue.text) self.check_data.append([inputs, outputs]) else: raise ValueError("Unknown tag: %s" % child.tag) else: if not isinstance(child, etree._Comment): print('not str:', idx, child.tag, child.attrib, child.text) pruned_extra_assignments = {} for assigned_var in self.extra_assignments.keys(): if self.extra_assignments[assigned_var] is not None: # if it was assigned keep it if hasattr(self.extra_assignments[assigned_var], 'shape'): if (self.extra_assignments[assigned_var].shape == (1,)): pruned_extra_assignments[sp.Array([assigned_var])] = self.extra_assignments[assigned_var] else: # TODO: need to figure out how to define a single symbol as a matrix/array with shape # TODO: and whatever that syntax is, it needs to make sure this works/has a fix raise ValueError("Cannot handle assignment of non-scalar shaped functions'") else: pruned_extra_assignments[assigned_var] = self.extra_assignments[assigned_var] # and remove from constants if present self.constants.pop(assigned_var, None) elif (assigned_var not in self.constants and assigned_var not in self.input_vars): # not assigned and not in constant warnings.warn("%s was never assigned, treating as input" % assigned_var) self.input_vars.append(assigned_var) # if unassigned but in constants, don't add to pruned so it is fetched from constants self.extra_assignments = pruned_extra_assignments print("Completed")
xx = np.linspace(-.25, 1.25, 64) yy = np.linspace(-.25, 1.25, 64) k = 3 meshx, meshy = np.meshgrid(x, y, indexing='ij') gridxy = np.stack((meshx, meshy), axis=-1) meshxx, meshyy = np.meshgrid(xx, yy, indexing='ij') gridxxyy = np.stack((meshxx, meshyy), axis=-1) for func in funcs: fvals = func(meshx, meshy) truef = func(meshxx, meshyy) test_NDBspline = ndsplines.make_interp_spline( gridxy, fvals, ) test_RectSpline = interpolate.RectBivariateSpline(x, y, fvals) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot_wireframe(meshxx, meshyy, truef, alpha=0.25, color='C0') ax.plot_wireframe(meshxx, meshyy, test_NDBspline(gridxxyy), color='C1') ax.plot_wireframe(meshxx, meshyy, test_RectSpline(meshxx, meshyy, grid=False), color='C2') plt.show()
from iminuit import Minuit dat1 = np.loadtxt("./GRID_05.dat") datlist = [dat1] for dat in datlist: dat.shape = (10, 10, 10, 10, 10, 6) p1 = dat1[:, 0, 0, 0, 0, 0] p2 = dat1[0, :, 0, 0, 0, 1] p3 = dat1[0, 0, :, 0, 0, 2] p4 = dat1[0, 0, 0, :, 0, 3] p5 = dat1[0, 0, 0, 0, :, 4] interpfun1 = ndsplines.make_interp_spline((p1, p2, p3, p4, p5), dat1[:, :, :, :, :, -1]) #interpfun2 = ndsplines.make_interp_spline((p1,p2,p3,p4,p5), dat2[:,:,:,:,:,-1]) #interpfun3 = ndsplines.make_interp_spline((p1,p2,p3,p4,p5), dat3[:,:,:,:,:,-1]) #interpfun4 = ndsplines.make_interp_spline((p1,p2,p3,p4,p5), dat4[:,:,:,:,:,-1]) #interpfun5 = ndsplines.make_interp_spline((p1,p2,p3,p4,p5), dat5[:,:,:,:,:,-1]) def single(x): return interpfun1(np.array([x[0], x[1], x[2], x[3], x[4]])) #return interpfun1(np.array([x[0], x[1], x[2], x[3], x[4] ])) #def sumxhi(x): # return ( interpfun1(np.array([x[0], x[1], x[2], x[3], x[4] ])) # +interpfun2(np.array([x[0], x[1], x[2], x[3], x[4] ]))
for func in funcs: fvals = func(meshx, meshy) truef = func(meshxx, meshyy) tidy_array = np.concatenate(( fvals.reshape((-1, 1)), tidyxy, ), axis=1) tidy_df = pd.DataFrame(tidy_array, columns=[ 'z', 'x', 'y', ]) test_NDBspline3 = ndsplines.make_interp_spline(gridxy, fvals[:, :, None]) test_NDBspline = ndsplines.make_interp_spline_from_tidy( tidy_df, ['x', 'y'], ['z']) test_RectSpline = interpolate.RectBivariateSpline(x, y, fvals) test_NDBspline2 = ndsplines.make_interp_spline_from_tidy( tidy_array, [1, 2], [0]) print(np.allclose(test_NDBspline2(gridxxyy), test_NDBspline(gridxxyy))) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot_wireframe(meshxx, meshyy, truef, alpha=0.25, color='C0') ax.plot_wireframe(meshxx, meshyy, test_NDBspline(gridxxyy)[..., 0],
sparse_data[xidx + 3, :], 'o', color='C%d' % xidx, label='x=%.1f' % x[xidx + 3], ) axes[1].legend() axes[1].set_xlabel('y') plt.show() # evaluate a function to interpolate over input grid meshf = np.sin(meshx) * (meshy - 3 / 8)**2 + 2 # create the interpolating splane interp = ndsplines.make_interp_spline(gridxy, meshf) # evaluate spline over denser grid meshff = interp(gridxxyy) plots(meshf, meshff) ## # as subplots fig, axes = plt.subplots(1, 2, constrained_layout=True) gridxxy = np.stack(np.meshgrid(xx, y, indexing='ij'), axis=-1) meshff = interp(gridxxy) for yidx in range(meshf.shape[1]):
t_ndspl = 10e3 * timeit( ndsplines.make_interp_spline, x=[x, y], y=z, n_iter=n_iter) t_scipy_build[:, i] = np.mean(t_scipy), np.std(t_scipy) t_ndspl_build[:, i] = np.mean(t_ndspl), np.std(t_ndspl) # spline query timing x, y, z = gen_xyz(7, 5) xx_sizes = np.logspace(0, 2, 10, dtype=int) t_scipy_call = np.empty((2, xx_sizes.size)) t_ndspl_npy_call = np.empty((2, xx_sizes.size)) t_ndspl_pyx_call = np.empty((2, xx_sizes.size)) for i, size in enumerate(xx_sizes): xx, yy = gen_xxyy(size, size) xxyy = np.stack((xx, yy), axis=-1) spl_scipy = interpolate.RectBivariateSpline(x.copy(), y.copy(), z) spl_ndspl = ndsplines.make_interp_spline((x, y), z) spl_ndspl.allocate_workspace_arrays(size) t_scipy = 10e3 * timeit( spl_scipy, x=xx.copy(), y=yy.copy(), grid=False, n_iter=n_iter) ndsplines.set_impl('cython') t_ndspl_pyx = 10e3 * timeit(spl_ndspl, x=xxyy, n_iter=n_iter) ndsplines.set_impl('numpy') t_ndspl_npy = 10e3 * timeit(spl_ndspl, x=xxyy, n_iter=n_iter) t_scipy_call[:, i] = np.mean(t_scipy), np.std(t_scipy) t_ndspl_pyx_call[:, i] = np.mean(t_ndspl_pyx), np.std(t_ndspl_pyx) t_ndspl_npy_call[:, i] = np.mean(t_ndspl_npy), np.std(t_ndspl_npy) # plot results fig, axes = plt.subplots(nrows=2) axes[0].errorbar(x_sizes,