Source code for funclp.modules.Function_LP._functions.splines.Spline

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Date          : 2026-01-01
# Author        : Lancelot PINCET
# GitHub        : https://github.com/LancelotPincet
# Library       : funcLP



# %% Libraries
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline
from funclp import Function, Parameter, ufunc
from corelp import rfrom
bspline1d, bspline1d_dx, get_mean, get_amp, get_offset = rfrom("._splines", "bspline1d", "bspline1d_dx", "get_mean", "get_amp", "get_offset")



# %% Parameters

def mu(res, *vars) :
    return get_mean(res, vars[0])
def amp(res, *vars) :
    return get_amp(res)
def offset(res, *vars) :
    return get_offset(res)

# %% Function

[docs] class Spline(Function): def __init__(self, model2interp=None, x2interp=None, k=3, /, **kwargs): if k > 5: raise ValueError('Spline of order higher than 5 is not implemented') if model2interp is not None and x2interp is not None: k = int(k) # Flatten coordinate arrays — accepts any broadcast shape x2interp = np.asarray(x2interp).ravel() model2interp = np.asarray(model2interp).ravel() if model2interp.shape != (len(x2interp),): raise ValueError( f'model2interp must have shape (nx,) = ' f'({len(x2interp)},), got {model2interp.shape}' ) spline = InterpolatedUnivariateSpline(x2interp, model2interp, k=k) # _eval_args[0] is the full knot vector (with k+1 boundary repetitions) # get_knots() returns interior only — do NOT use it here t = spline._eval_args[0].astype(np.float32) # get_coeffs() already has length len(t)-k-1, correctly trimmed coeffs = spline.get_coeffs().astype(np.float32) super().__init__(k=k, t=t, coeffs=coeffs) @ufunc( variables=["x"], parameters=[ Parameter("mu", 0., estimate=mu), Parameter("amp", 1., estimate=amp), Parameter("offset", 0., estimate=offset), Parameter("k", 3), ], constants=["t", "coeffs"], ) def function(x, /, mu=0., amp=1., offset=0., k=3, t=None, coeffs=None) : return amp * bspline1d(t, coeffs, k, x-mu) + offset @ufunc(constants=["t", "coeffs"]) def d_mu(x, /, mu, amp, offset, k=3, t=None, coeffs=None): return -amp * bspline1d_dx(t, coeffs, k, x - mu) @ufunc(constants=["t", "coeffs"]) def d_amp(x, /, mu, amp, offset, k=3, t=None, coeffs=None): return bspline1d(t, coeffs, k, x - mu) @ufunc(constants=["t", "coeffs"]) def d_offset(x, /, mu, amp, offset, k=3, t=None, coeffs=None): return np.float32(1.0) def _cpu_assembly_extra_imports_source(self, estimator, function_name, estimator_name, distribution_name, parameters): return "from funclp.modules.Function_LP._functions.splines._splines import bspline1d, bspline1d_dx" def _cpu_assembly_model_setup_source(self, model_params, parameters): return '''model_mu = mu[model] model_amp = amp[model] model_offset = offset[model] model_k = k[model]''' def _cpu_assembly_model_eval_source(self, inputs_scalar): return ''' base = bspline1d(t, coeffs, model_k, point_x - model_mu) mod = model_amp * base + model_offset dev = deviance_scalar(point_raw_data, mod, point_weight) los = loss_scalar(point_raw_data, mod, point_weight) fis = fisher_scalar(point_raw_data, mod, point_weight) chi_local += dev''' def _cpu_assembly_derivatives_source(self, parameters, inputs_scalar): return ''' if bool2fit[0]: jacob_local[count] = -model_amp * bspline1d_dx(t, coeffs, model_k, point_x - model_mu) count += 1 if bool2fit[1]: jacob_local[count] = base count += 1 if bool2fit[2]: jacob_local[count] = 1.0 count += 1 if bool2fit[3]: jacob_local[count] = d_k(point_x, model_mu, model_amp, model_offset, model_k, t, coeffs) count += 1''' def _gpu_assembly_derivatives_source(self, parameters, inputs_threads): return ''' if bool2fit[0]: jacob_local[count] = d_mu(thread_x, block_mu, block_amp, block_offset, block_k, t, coeffs) count += 1 if bool2fit[1]: jacob_local[count] = d_amp(thread_x, block_mu, block_amp, block_offset, block_k, t, coeffs) count += 1 if bool2fit[2]: jacob_local[count] = d_offset(thread_x, block_mu, block_amp, block_offset, block_k, t, coeffs) count += 1 if bool2fit[3]: jacob_local[count] = d_k(thread_x, block_mu, block_amp, block_offset, block_k, t, coeffs) count += 1'''
# %% Test function run if __name__ == "__main__": from corelp import debug from funclp import plot import numpy as np debug_folder = debug(__file__) # Inputs variables = ( np.linspace(-1, 1, 1000).reshape((1,1000)), ) parameters = dict() # Get interpolation from funclp import Gaussian gausfunction = Gaussian() model = gausfunction(*variables) # Plot function instance = Spline(model, *variables) plot(instance, debug_folder, (variables[0] + 0.5), parameters)