From d3fd84a2f9ee2109f4f86c3dead1502e54e27669 Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 12:15:51 +0000 Subject: [PATCH 01/52] replace model class with jax jit compiled models --- Basin-hopping_Nelder-Mead/BHNM/msf_fit.py | 255 ------------------ Basin-hopping_Nelder-Mead/times_chis.py | 120 --------- Basin-hopping_Nelder-Mead/x_data_for_comp.txt | 100 ------- Basin-hopping_Nelder-Mead/y_data_for_comp.txt | 100 ------- maxsmooth/Models.py | 118 +++----- requirements.txt | 5 - setup.py | 37 --- 7 files changed, 38 insertions(+), 697 deletions(-) delete mode 100644 Basin-hopping_Nelder-Mead/BHNM/msf_fit.py delete mode 100644 Basin-hopping_Nelder-Mead/times_chis.py delete mode 100644 Basin-hopping_Nelder-Mead/x_data_for_comp.txt delete mode 100644 Basin-hopping_Nelder-Mead/y_data_for_comp.txt delete mode 100644 requirements.txt delete mode 100644 setup.py diff --git a/Basin-hopping_Nelder-Mead/BHNM/msf_fit.py b/Basin-hopping_Nelder-Mead/BHNM/msf_fit.py deleted file mode 100644 index 967239c..0000000 --- a/Basin-hopping_Nelder-Mead/BHNM/msf_fit.py +++ /dev/null @@ -1,255 +0,0 @@ -import numpy as np -from scipy.optimize import minimize, basinhopping -import sys - - -class max_fit_BH(object): - def __init__(self, x, y, N, mid_point, **kwargs): - - self.step_size = kwargs.pop('step_size', 0.5) - self.temp = kwargs.pop('temp', 1) - self.interval = kwargs.pop('interval', 50) - self.normalisation = kwargs.pop('data_norm', True) - - if self.normalisation is True: - self.x = x/x.max() - self.true_x = x - self.y = y/y.std() + y.mean() / y.std() - self.true_y = y - else: - self.x = x - self.y = y - - self.N = N - self.mid_point = mid_point - - self.fit_result = self.fit() - - def fit(self): - - def func1(params): - y_sum = self.y[self.mid_point] * np.sum([ - params[i] * (self.x / self.x[self.mid_point])**i - for i in range(self.N)], axis=0) - message = 'test' - const = constraint(params, message) - if const == 1: - return np.sum((self.y - y_sum)**2) - if const == -1: - return np.sum((self.y - y_sum)**2)+1e80 - - def constraint(params, message): - - m = np.arange(0, self.N, 1) - deriv = [] - for j in range(len(m)): - if m[j] >= 2: - dif = [] - for i in range(self.N - m[j]): - if i <= (self.N - m[j]): - dif_m_bit = ( - self.y[self.mid_point] / - self.x[self.mid_point]) * \ - np.math.factorial(m[j]+i) / \ - np.math.factorial(i) * \ - params[m[j]+i]*(self.x)**i / \ - (self.x[self.mid_point])**(i+1) - dif.append(dif_m_bit) - dif = np.array(dif) - derivative = dif.sum(axis=0) - deriv.append([m[j], derivative]) - deriv = np.array(deriv) - derive = [] - for i in range(deriv.shape[0]): - derive.append(deriv[i, 1]) - derive = np.array(derive) - pass_fail = [] # 1==pass, 0==fail - for i in range(derive.shape[0]): - if np.any(derive[i, :] == 1e-7): - pass_fail.append(0) - elif np.any(derive[i, :] > -1e-7) and \ - np.any(derive[i, :] < 1e-7): - pass_fail.append(0) - else: - pass_fail.append(1) - pass_fail = np.array(pass_fail) - - if np.any(pass_fail == 0): - const = -1 # failed - else: - const = 1 # satisfied - - return const - - params0 = [(self.y[-1]-self.y[0])/2]*(self.N) - res = basinhopping( - func1, params0, niter=10000, niter_success=100*self.N, - stepsize=self.step_size, T=self.temp, interval=self.interval, - seed=1) - print('msf fit params', res) - - parameters = res.x.copy() - if self.normalisation is True: - for i in range(len(parameters)): - if i == 0: - parameters[i] = parameters[i] * \ - (1+self.true_y.mean()/self.true_y[self.mid_point]) \ - - self.true_y.mean()/(self.true_y[self.mid_point]) - else: - parameters[i] = parameters[i] * \ - (1+self.true_y.mean()/self.true_y[self.mid_point]) - - message = 'summary' - const = constraint(parameters, message) - if const != 1: - print('Error: condition violated') - sys.exit(1) - - def fitting(params): - if self.normalisation is True: - y_sum = self.true_y[self.mid_point]*np.sum([ - params[i]*(self.true_x/self.true_x[self.mid_point])**i - for i in range(self.N)], axis=0) - else: - y_sum = self.y[self.mid_point]*np.sum([ - params[i]*(self.x/self.x[self.mid_point])**i - for i in range(self.N)], axis=0) - return y_sum - - fitted_y = fitting(parameters) - if self.normalisation is True: - print('chi BH', np.sum((self.true_y-fitted_y)**2)) - else: - print('chi BH', np.sum((self.y-fitted_y)**2)) - - return res.x - - -class max_fit_NM(object): - def __init__(self, x, y, N, BH_params, mid_point, **kwargs): - - self.normalisation = kwargs.pop('data_norm', True) - - if self.normalisation is True: - self.x = x/x.max() - self.true_x = x - self.y = y/y.std() + y.mean()/y.std() - self.true_y = y - else: - self.x = x - self.y = y - - self.N = N - self.BH_params = BH_params - self.mid_point = mid_point - self.fit_result, self.fit_h, self.chi = self.fit() - - def fit(self): - print('-------------------------------------------------------------') - - def func1(params): - y_sum = self.y[self.mid_point]*np.sum([ - params[i]*(self.x/self.x[self.mid_point])**i - for i in range(self.N)], axis=0) - message = 'test' - const, h = constraint(params, message) - if const == 1: - return np.sum((self.y-y_sum)**2) - if const == -1: - return np.sum((self.y-y_sum)**2)+1e80 - - def constraint(params, message): - - m = np.arange(0, self.N, 1) - deriv = [] - for j in range(len(m)): - if m[j] >= 2: - dif = [] - for i in range(self.N-m[j]): - if i <= (self.N-m[j]): - dif_m_bit = ( - self.y[self.mid_point] / - self.x[self.mid_point]) * \ - np.math.factorial(m[j]+i) / \ - np.math.factorial(i) * \ - params[m[j]+i]*(self.x)**i / \ - (self.x[self.mid_point])**(i+1) - dif.append(dif_m_bit) - dif = np.array(dif) - derivative = dif.sum(axis=0) - deriv.append([m[j], derivative]) - deriv = np.array(deriv) - derive = [] - for i in range(deriv.shape[0]): - derive.append(deriv[i, 1]) - derive = np.array(derive) - if message == 'summary': - print('min derivative', derive.min()) - h = np.abs(derive).min()/2 - if message == 'test': - h = None - pass - pass_fail = [] # 1==pass, 0==fail - for i in range(derive.shape[0]): - if np.any(derive[i, :] == 1e-7): - pass_fail.append(0) - elif np.any(derive[i, :] > -1e-7) and \ - np.any(derive[i, :] < 1e-7): - pass_fail.append(0) - else: - pass_fail.append(1) - pass_fail = np.array(pass_fail) - - if np.any(pass_fail == 0): - const = -1 # failed - else: - const = 1 # satisfied - - return const, h - - def fitting(params): - if self.normalisation is True: - y_sum = self.true_y[self.mid_point]*np.sum([ - params[i]*(self.true_x/self.true_x[self.mid_point])**i - for i in range(self.N)], axis=0) - else: - y_sum = self.y[self.mid_point]*np.sum([ - params[i]*(self.x/self.x[self.mid_point])**i - for i in range(self.N)], axis=0) - return y_sum - - params0 = self.BH_params - - res = minimize( - func1, params0, - options={ - 'maxiter': 100000, 'adaptive': True, 'fatol': 1e-7, - 'xatol': 1e-7}, method='Nelder-Mead') - print(res) - - parameters = res.x - if self.normalisation is True: - for i in range(len(parameters)): - if i == 0: - parameters[i] = parameters[i] * \ - (1+self.true_y.mean()/self.true_y[self.mid_point]) \ - - self.true_y.mean()/(self.true_y[self.mid_point]) - else: - parameters[i] = parameters[i] * \ - (1+self.true_y.mean()/self.true_y[self.mid_point]) - - fitted_y = fitting(parameters) - if self.normalisation is True: - print('chi NM', np.sum((self.true_y-fitted_y)**2)) - chi = np.sum((self.true_y-fitted_y)**2) - else: - print('chi NM', np.sum((self.y-fitted_y)**2)) - chi = np.sum((self.y-fitted_y)**2) - - message = 'summary' - const, h = constraint(parameters, message) - if const != 1: - print('Error: condition violated') - sys.exit(1) - - return parameters, h, chi diff --git a/Basin-hopping_Nelder-Mead/times_chis.py b/Basin-hopping_Nelder-Mead/times_chis.py deleted file mode 100644 index bc8f232..0000000 --- a/Basin-hopping_Nelder-Mead/times_chis.py +++ /dev/null @@ -1,120 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from maxsmooth.DCF import smooth -from BHNM.msf_fit import max_fit_BH, max_fit_NM -import time - - -def fit(params, mid_point, x, y, N): - y_sum = y[mid_point]*np.sum([ - params[i]*(x/x[mid_point])**i - for i in range(N)], axis=0) - return y_sum - - -"""x = np.linspace(1, 5, 100) -noise = np.random.normal(0,0.5,len(x)) -y = 0.6+2*x+4*x**(3)+9*x**(4)+noise""" - -x = np.loadtxt('x_data_for_comp.txt') -y = np.loadtxt('y_data_for_comp.txt') - -N = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] - -# Testing all signs -times_qp = [] -chi_qp = [] -for i in range(len(N)): - s = time.time() - result = smooth( - x, y, N[i], model_type='normalised_polynomial', fit_type='qp') - e = time.time() - times_qp.append(e-s) - chi_qp.append(result.optimum_chi) - -# Using the maxsmooth sign navigating algorithm -times_qpsf = [] -chi_qpsf = [] -for i in range(len(N)): - s = time.time() - result = smooth(x, y, N[i], model_type='normalised_polynomial') - e = time.time() - times_qpsf.append(e-s) - chi_qpsf.append(result.optimum_chi) - -np.savetxt('times_qp_for_comp.txt', times_qp) -np.savetxt('times_qpsf_for_comp.txt', times_qpsf) -np.savetxt('chi_qp_for_comp.txt', chi_qp) -np.savetxt('chi_qpsf_for_comp.txt', chi_qpsf) - -# Basin-hopping followed by a Nelder-Mead routine -N_BHNM = np.arange(3, 8, 1) -mid_point = len(x)//2 -BHNM_chis_defualt = [] -BHNM_times_defualt = [] -h = [] -for i in range(len(N_BHNM)): - s = time.time() - BH = max_fit_BH( - x, y, N_BHNM[i], mid_point, step_size=10*N_BHNM[i], - interval=50, temp=5 * N_BHNM[i]) - NM = max_fit_NM(x, y, N_BHNM[i], BH.fit_result, mid_point) - fitted_y = fit(NM.fit_result, mid_point, x, y, N_BHNM[i]) - e = time.time() - print( - 'N:', N_BHNM[i], 'TIME:', e-s, 'CHI_RATIO:', - np.sum((y-fitted_y)**2)/chi_qpsf[i]) - print('CHI_BHNM:', np.sum((y-fitted_y)**2), 'CHI_QP:', chi_qpsf[i]) - chi = np.sum((y-fitted_y)**2) - BHNM_chis_defualt.append(chi) - BHNM_times_defualt.append(e-s) - -np.save('BHNM_times.npy', BHNM_times_defualt) -np.save('BHNM_chis.npy', BHNM_chis_defualt) - -chi_qp_plotting = [] -for i in range(len(N)): - if N[i] <= N_BHNM.max(): - chi_qp_plotting.append(chi_qpsf[i]) - -ratio = [] -for i in range(len(BHNM_chis_defualt)): - ratio.append(BHNM_chis_defualt[i]/chi_qp_plotting[i]) - -plt.subplot(111) -plt.plot(N_BHNM, ratio, ls='-', c='k') -plt.xlabel('N', fontsize=12) -plt.ylabel( - r'$\frac{X^2_{Basinhopping + Nelder-Mead}}{X^2_{QP Sampling Sign Space}}$', - fontsize=12) -plt.tight_layout() -plt.savefig('chi_ratio.pdf') -plt.close() - -plt.subplot(111) -plt.plot(N, times_qp, ls='-', label='QP Testing All Sign Combinations', c='g') -plt.plot(N, times_qpsf, ls='-', label='QP Sampling Sign Space', c='k') -plt.plot( - N_BHNM, BHNM_times_defualt, - ls='-', label='Basinhopping + Nelder-Mead\n', c='r') -plt.xlabel('N', fontsize=12) -plt.ylabel(r'$t$ [s]', fontsize=12) -plt.yscale('log') -plt.legend(loc=0) -plt.tight_layout() -plt.savefig('Times.pdf') -plt.close() - -plt.subplot(111) -plt.plot(N, chi_qp, ls='-', label='QP Testing All Sign Combinations', c='g') -plt.plot(N, chi_qpsf, ls='-', label='QP Sampling Sign Space', c='k') -plt.plot( - N_BHNM, BHNM_chis_defualt, - ls='-', label='Basinhopping + Nelder-Mead', c='r') -plt.xlabel('N', fontsize=12) -plt.ylabel(r'$X^2$', fontsize=12) -plt.yscale('log') -plt.legend(loc=0) -plt.tight_layout() -plt.savefig('chi.pdf') -plt.close() diff --git a/Basin-hopping_Nelder-Mead/x_data_for_comp.txt b/Basin-hopping_Nelder-Mead/x_data_for_comp.txt deleted file mode 100644 index 9f718a4..0000000 --- a/Basin-hopping_Nelder-Mead/x_data_for_comp.txt +++ /dev/null @@ -1,100 +0,0 @@ -1.000000000000000000e+00 -1.040404040404040442e+00 -1.080808080808080884e+00 -1.121212121212121104e+00 -1.161616161616161547e+00 -1.202020202020201989e+00 -1.242424242424242431e+00 -1.282828282828282873e+00 -1.323232323232323315e+00 -1.363636363636363757e+00 -1.404040404040403978e+00 -1.444444444444444420e+00 -1.484848484848484862e+00 -1.525252525252525304e+00 -1.565656565656565746e+00 -1.606060606060605966e+00 -1.646464646464646631e+00 -1.686868686868686851e+00 -1.727272727272727293e+00 -1.767676767676767735e+00 -1.808080808080808177e+00 -1.848484848484848619e+00 -1.888888888888888840e+00 -1.929292929292929504e+00 -1.969696969696969724e+00 -2.010101010101010388e+00 -2.050505050505050608e+00 -2.090909090909090828e+00 -2.131313131313131493e+00 -2.171717171717171713e+00 -2.212121212121211933e+00 -2.252525252525252597e+00 -2.292929292929293261e+00 -2.333333333333333481e+00 -2.373737373737373701e+00 -2.414141414141414366e+00 -2.454545454545454586e+00 -2.494949494949494806e+00 -2.535353535353535470e+00 -2.575757575757576134e+00 -2.616161616161616355e+00 -2.656565656565656575e+00 -2.696969696969697239e+00 -2.737373737373737459e+00 -2.777777777777777679e+00 -2.818181818181818343e+00 -2.858585858585859008e+00 -2.898989898989899228e+00 -2.939393939393939448e+00 -2.979797979797980112e+00 -3.020202020202020332e+00 -3.060606060606060996e+00 -3.101010101010101216e+00 -3.141414141414141437e+00 -3.181818181818182101e+00 -3.222222222222222321e+00 -3.262626262626262985e+00 -3.303030303030303205e+00 -3.343434343434343425e+00 -3.383838383838384090e+00 -3.424242424242424310e+00 -3.464646464646464974e+00 -3.505050505050505194e+00 -3.545454545454545858e+00 -3.585858585858586078e+00 -3.626262626262626299e+00 -3.666666666666666963e+00 -3.707070707070707183e+00 -3.747474747474747847e+00 -3.787878787878788067e+00 -3.828282828282828731e+00 -3.868686868686868952e+00 -3.909090909090909172e+00 -3.949494949494949836e+00 -3.989898989898990056e+00 -4.030303030303031164e+00 -4.070707070707070940e+00 -4.111111111111110716e+00 -4.151515151515152269e+00 -4.191919191919192045e+00 -4.232323232323232709e+00 -4.272727272727273373e+00 -4.313131313131313149e+00 -4.353535353535353813e+00 -4.393939393939394478e+00 -4.434343434343434254e+00 -4.474747474747474918e+00 -4.515151515151515582e+00 -4.555555555555555358e+00 -4.595959595959596911e+00 -4.636363636363636687e+00 -4.676767676767676463e+00 -4.717171717171718015e+00 -4.757575757575757791e+00 -4.797979797979798455e+00 -4.838383838383839120e+00 -4.878787878787878896e+00 -4.919191919191919560e+00 -4.959595959595960224e+00 -5.000000000000000000e+00 diff --git a/Basin-hopping_Nelder-Mead/y_data_for_comp.txt b/Basin-hopping_Nelder-Mead/y_data_for_comp.txt deleted file mode 100644 index 0b4c8c2..0000000 --- a/Basin-hopping_Nelder-Mead/y_data_for_comp.txt +++ /dev/null @@ -1,100 +0,0 @@ -1.538480190059443231e+01 -1.803994844410931719e+01 -2.074192622407534614e+01 -2.340100984140073592e+01 -2.621510063558880432e+01 -2.887939230577280370e+01 -3.267760037624015723e+01 -3.624293586100588982e+01 -4.183230771978232099e+01 -4.472484203235710254e+01 -4.901901109503933185e+01 -5.458384801381982498e+01 -6.044395282904604727e+01 -6.710163163497058747e+01 -7.331305934512305100e+01 -8.038417701150292771e+01 -8.828937593277244389e+01 -9.658444786378277058e+01 -1.042045848601506322e+02 -1.146416307471176879e+02 -1.235112892305587451e+02 -1.345268586166006060e+02 -1.450430823504431430e+02 -1.581643332442427266e+02 -1.717913514750528066e+02 -1.835712719659944128e+02 -1.979150031939569203e+02 -2.139361084172272456e+02 -2.295680700846963020e+02 -2.465373692074055327e+02 -2.641143352719346922e+02 -2.831127401702224233e+02 -3.022997542458672910e+02 -3.228565015249954513e+02 -3.445193178888176249e+02 -3.676949607788102412e+02 -3.913593215276684418e+02 -4.168242323983324695e+02 -4.426368502745826845e+02 -4.702519040672153210e+02 -4.999275768833090865e+02 -5.289023404506694988e+02 -5.603229923493009892e+02 -5.931106443932800403e+02 -6.271303491261907084e+02 -6.633693290327342993e+02 -7.017142035218076899e+02 -7.397376073564449825e+02 -7.806386443959225971e+02 -8.228136223978054886e+02 -8.656723069434885929e+02 -9.102137208256813210e+02 -9.580326031355238001e+02 -1.007291992119634074e+03 -1.058029537451610622e+03 -1.111047519335722654e+03 -1.166443910326044715e+03 -1.222809821319707908e+03 -1.281110152112206606e+03 -1.342530443746999026e+03 -1.405175264221236603e+03 -1.471403152526458143e+03 -1.536878719515193097e+03 -1.608101102592653660e+03 -1.679812150650684544e+03 -1.754709199343822320e+03 -1.832464343650941828e+03 -1.911709046912803842e+03 -1.994382101504000275e+03 -2.078654055364936994e+03 -2.166598274438367753e+03 -2.255622982675686217e+03 -2.348654835621773600e+03 -2.444463611754800695e+03 -2.543845966417291038e+03 -2.645305246365588118e+03 -2.749656581282604748e+03 -2.858029640524120168e+03 -2.968665196804036896e+03 -3.083208241631706187e+03 -3.198777704047548468e+03 -3.320655724687552720e+03 -3.444593388278271505e+03 -3.572310906936728770e+03 -3.704479259388221635e+03 -3.838077949702294973e+03 -3.975746853596534947e+03 -4.118423306260904610e+03 -4.263847070864699162e+03 -4.413647032393576410e+03 -4.567425210209468787e+03 -4.724884307810286373e+03 -4.886477595104389366e+03 -5.051962838680952700e+03 -5.220691820972367168e+03 -5.395668600079392490e+03 -5.574189572375433272e+03 -5.756885988219393766e+03 -5.943798781023513584e+03 -6.134840236402888877e+03 diff --git a/maxsmooth/Models.py b/maxsmooth/Models.py index 329f3d0..ce0f2ce 100755 --- a/maxsmooth/Models.py +++ b/maxsmooth/Models.py @@ -1,80 +1,38 @@ -import numpy as np -from scipy.special import legendre - - -class Models_class(object): - def __init__(self, params, x, y, N, pivot_point, model_type, new_basis): - self.x = x - self.y = y - self.N = N - self.params = params - self.pivot_point = pivot_point - self.model_type = model_type - self.model = new_basis['model'] - self.args = new_basis['args'] - self.y_sum = self.fit() - - def fit(self): - - if self.model is None: - if self.model_type == 'normalised_polynomial': - - y_sum = self.y[self.pivot_point]*np.sum([ - self.params[i]*(self.x/self.x[self.pivot_point])**i - for i in range(self.N)], axis=0) - - if self.model_type == 'polynomial': - - y_sum = np.sum( - [self.params[i]*(self.x)**i for i in range(self.N)], - axis=0) - - if self.model_type == 'loglog_polynomial': - - y_sum = 10**(np.sum([ - self.params[i]*np.log10(self.x)**i - for i in range(self.N)], - axis=0)) - - if self.model_type == 'exponential': - - y_sum = self.y[self.pivot_point]*np.sum([ - self.params[i] * - np.exp(-i*self.x/self.x[self.pivot_point]) - for i in range(self.N)], - axis=0) - - if self.model_type == 'log_polynomial': - - y_sum = np.sum([ - self.params[i] * - np.log10(self.x/self.x[self.pivot_point])**i - for i in range(self.N)], - axis=0) - - if self.model_type == 'difference_polynomial': - - y_sum = np.sum([ - self.params[i]*(self.x-self.x[self.pivot_point])**i - for i in range(self.N)], axis=0) - - if self.model_type == 'legendre': - - interval = np.linspace(-0.999, 0.999, len(self.x)) - lps = [] - for n in range(self.N): - P = legendre(n) - lps.append(P(interval)) - lps = np.array(lps) - y_sum = np.sum([ - self.params[i] * lps[i] for i in range(self.N)], axis=0) - - if self.model is not None: - if self.args is None: - y_sum = self.model( - self.x, self.y, self.pivot_point, self.N, self.params) - if self.args is not None: - y_sum = self.model( - self.x, self.y, self.pivot_point, self.N, self.params, - *self.args) - return y_sum +from jax import numpy as jnp +import jax + +@jax.jit +def normalised_polynomial(x, y, N, pivot_point, params): + y_sum = y[pivot_point]*jnp.sum(jnp.array([ + params[i]*(x/x[pivot_point])**i for i in range(N)]), axis=0) + return y_sum + +@jax.jit +def polynomial(x, y, N, pivot_point, params): + y_sum = jnp.sum(jnp.array([ + params[i]*(x)**i for i in range(N)]), axis=0) + return y_sum + +@jax.jit +def loglog_polynomial(x, y, N, pivot_point, params): + y_sum = 10**(jnp.sum(jnp.array([ + params[i]*jnp.log10(x)**i for i in range(N)]), axis=0)) + return y_sum + +@jax.jit +def exponential(x, y, N, pivot_point, params): + y_sum = y[pivot_point]*jnp.sum(jnp.array([ + params[i]*jnp.exp(-i*x/x[pivot_point]) for i in range(N)]), axis=0) + return y_sum + +@jax.jit +def log_polynomial(x, y, N, pivot_point, params): + y_sum = jnp.sum(jnp.array([ + params[i]*jnp.log10(x/x[pivot_point])**i for i in range(N)]), axis=0) + return y_sum + +@jax.jit +def difference_polynomial(x, y, N, pivot_point, params): + y_sum = jnp.sum(jnp.array([ + params[i]*(x - x[pivot_point])**i for i in range(N)]), axis=0) + return y_sum diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 0552818..0000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -matplotlib -numpy -CVXOPT -scipy -progressbar diff --git a/setup.py b/setup.py deleted file mode 100644 index d59754f..0000000 --- a/setup.py +++ /dev/null @@ -1,37 +0,0 @@ -from setuptools import setup, find_packages - - -def readme(short=False): - with open('README.rst') as f: - if short: - return f.readlines()[1].strip() - else: - return f.read() - -setup( - name='maxsmooth', - version='1.2.1', - description='maxsmooth:Derivative Constrained Function Fitting', - long_description=readme(), - author='Harry T. J. Bevins', - author_email='htjb2@cam.ac.uk', - url='https://github.com/htjb/maxsmooth', - packages=find_packages(), - install_requires=['numpy', 'scipy', 'cvxopt', 'matplotlib', 'progressbar'], - license='MIT', - extras_require={ - 'docs': ['sphinx', 'sphinx_rtd_theme', 'numpydoc'], - }, - tests_require=['pytest'], - classifiers=[ - 'Intended Audience :: Science/Research', - 'Natural Language :: English', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Astronomy', - 'Topic :: Scientific/Engineering :: Physics', - ], -) From d9fe71fbb95364e9fdbb798e5f2790bedd66086f Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 12:16:22 +0000 Subject: [PATCH 02/52] more modern package set up with uv --- pyproject.toml | 14 ++ uv.lock | 530 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 544 insertions(+) create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..de57cb1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,14 @@ +[project] +name = "maxsmooth" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "cvxopt>=1.3.2", + "jax>=0.8.0", + "matplotlib>=3.10.7", + "numpy>=2.3.4", + "progressbar>=2.5", + "scipy>=1.16.3", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..bec8c69 --- /dev/null +++ b/uv.lock @@ -0,0 +1,530 @@ +version = 1 +revision = 2 +requires-python = ">=3.13" + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, +] + +[[package]] +name = "cvxopt" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/12/8467d16008ab7577259d32f1e59c4d84edda22b7729ab4a1a0dfd5f0550b/cvxopt-1.3.2.tar.gz", hash = "sha256:3461fa42c1b2240ba4da1d985ca73503914157fc4c77417327ed6d7d85acdbe6", size = 4108454, upload-time = "2023-08-09T14:31:17.514Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/c5/3e70e50c4c478acd3fefe3ea51b7e42ad661ce5a265a72b3dba175ce10fc/cvxopt-1.3.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:2f9135eea23c9b781574e0cadc5738cf5651a8fd8de822b6de1260411523bfd1", size = 16873224, upload-time = "2024-10-21T20:48:37.221Z" }, + { url = "https://files.pythonhosted.org/packages/61/96/e42b9ec38e1bbe9bf85a5fc9cc7feb173de5a874889735072b49a7d4d8d0/cvxopt-1.3.2-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d7921768712db156e6ec92ac21f7ce52069feb1fb994868d0ca795498111fbac", size = 12424739, upload-time = "2024-10-21T20:48:40.325Z" }, + { url = "https://files.pythonhosted.org/packages/32/08/2c621ad782e9ff7f921c2244c6b4bcbc72ca756cb33021295c288123c465/cvxopt-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af63db45ba559e3e15180fbec140d8a4ff612d8f21d989181a4e8479fa3b8b6", size = 17869707, upload-time = "2024-10-21T20:48:42.881Z" }, + { url = "https://files.pythonhosted.org/packages/62/60/583a1ef8e2e259bdd1bf32fccd4ea15aef4aad5854746ec59cbb2462eb92/cvxopt-1.3.2-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:8fe178ac780a8bccf425a08004d853eae43b3ddcf7617521fb35c63550077b17", size = 13846614, upload-time = "2024-10-21T20:48:46.26Z" }, + { url = "https://files.pythonhosted.org/packages/e4/2b/d8721b046a3c8bff494490a01ef1eeacf1f970f0d1274448856ccbe0475c/cvxopt-1.3.2-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a47a95d7848e6fe768b55910bac8bb114c5f1f355f5a6590196d5e9bdf775d2f", size = 21277032, upload-time = "2024-10-21T20:48:49.48Z" }, + { url = "https://files.pythonhosted.org/packages/6a/19/b1e1c16895a36cc504bf7a940e88431b82b18ca10cbce81072860b9e3d60/cvxopt-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e863238d64a4b4443b8be53a08f6b94eda6ec1727038c330da02014f7c19e1be", size = 9530674, upload-time = "2024-10-21T20:48:51.948Z" }, + { url = "https://files.pythonhosted.org/packages/42/cc/ac0705749f96cc52f8d30c9c06e54dc8d4c04ef9c2d21aeed1ae2ee63dab/cvxopt-1.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c56965415afd8a493cc4af3587960751f8780057ca3de8c6be97217156e4633", size = 13725340, upload-time = "2024-10-21T20:48:55.074Z" }, + { url = "https://files.pythonhosted.org/packages/76/f2/7e3c3f51e8e6b325bf00bfc37036f1f58bd9a5c29bbd88fb2eef2ebc0ac2/cvxopt-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:85c3b52c1353b294c597b169cc901f5274d8bb8776908ccad66fec7a14b69519", size = 16226402, upload-time = "2024-10-21T20:48:57.616Z" }, + { url = "https://files.pythonhosted.org/packages/b9/55/90b40b489a235a9f35a532eb77cec81782e466779d9a531ffda6b2f99410/cvxopt-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:0a0987966009ad383de0918e61255d34ed9ebc783565bcb15470d4155010b6bf", size = 12845323, upload-time = "2024-10-21T20:49:00.581Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "fonttools" +version = "4.60.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823, upload-time = "2025-09-29T21:13:27.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/5b/cdd2c612277b7ac7ec8c0c9bc41812c43dc7b2d5f2b0897e15fdf5a1f915/fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb", size = 2825777, upload-time = "2025-09-29T21:12:01.22Z" }, + { url = "https://files.pythonhosted.org/packages/d6/8a/de9cc0540f542963ba5e8f3a1f6ad48fa211badc3177783b9d5cadf79b5d/fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4", size = 2348080, upload-time = "2025-09-29T21:12:03.785Z" }, + { url = "https://files.pythonhosted.org/packages/2d/8b/371ab3cec97ee3fe1126b3406b7abd60c8fec8975fd79a3c75cdea0c3d83/fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c", size = 4903082, upload-time = "2025-09-29T21:12:06.382Z" }, + { url = "https://files.pythonhosted.org/packages/04/05/06b1455e4bc653fcb2117ac3ef5fa3a8a14919b93c60742d04440605d058/fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77", size = 4960125, upload-time = "2025-09-29T21:12:09.314Z" }, + { url = "https://files.pythonhosted.org/packages/8e/37/f3b840fcb2666f6cb97038793606bdd83488dca2d0b0fc542ccc20afa668/fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199", size = 4901454, upload-time = "2025-09-29T21:12:11.931Z" }, + { url = "https://files.pythonhosted.org/packages/fd/9e/eb76f77e82f8d4a46420aadff12cec6237751b0fb9ef1de373186dcffb5f/fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c", size = 5044495, upload-time = "2025-09-29T21:12:15.241Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b3/cede8f8235d42ff7ae891bae8d619d02c8ac9fd0cfc450c5927a6200c70d/fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272", size = 2217028, upload-time = "2025-09-29T21:12:17.96Z" }, + { url = "https://files.pythonhosted.org/packages/75/4d/b022c1577807ce8b31ffe055306ec13a866f2337ecee96e75b24b9b753ea/fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac", size = 2266200, upload-time = "2025-09-29T21:12:20.14Z" }, + { url = "https://files.pythonhosted.org/packages/9a/83/752ca11c1aa9a899b793a130f2e466b79ea0cf7279c8d79c178fc954a07b/fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3", size = 2822830, upload-time = "2025-09-29T21:12:24.406Z" }, + { url = "https://files.pythonhosted.org/packages/57/17/bbeab391100331950a96ce55cfbbff27d781c1b85ebafb4167eae50d9fe3/fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85", size = 2345524, upload-time = "2025-09-29T21:12:26.819Z" }, + { url = "https://files.pythonhosted.org/packages/3d/2e/d4831caa96d85a84dd0da1d9f90d81cec081f551e0ea216df684092c6c97/fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537", size = 4843490, upload-time = "2025-09-29T21:12:29.123Z" }, + { url = "https://files.pythonhosted.org/packages/49/13/5e2ea7c7a101b6fc3941be65307ef8df92cbbfa6ec4804032baf1893b434/fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003", size = 4944184, upload-time = "2025-09-29T21:12:31.414Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2b/cf9603551c525b73fc47c52ee0b82a891579a93d9651ed694e4e2cd08bb8/fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08", size = 4890218, upload-time = "2025-09-29T21:12:33.936Z" }, + { url = "https://files.pythonhosted.org/packages/fd/2f/933d2352422e25f2376aae74f79eaa882a50fb3bfef3c0d4f50501267101/fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99", size = 4999324, upload-time = "2025-09-29T21:12:36.637Z" }, + { url = "https://files.pythonhosted.org/packages/38/99/234594c0391221f66216bc2c886923513b3399a148defaccf81dc3be6560/fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6", size = 2220861, upload-time = "2025-09-29T21:12:39.108Z" }, + { url = "https://files.pythonhosted.org/packages/3e/1d/edb5b23726dde50fc4068e1493e4fc7658eeefcaf75d4c5ffce067d07ae5/fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987", size = 2270934, upload-time = "2025-09-29T21:12:41.339Z" }, + { url = "https://files.pythonhosted.org/packages/fb/da/1392aaa2170adc7071fe7f9cfd181a5684a7afcde605aebddf1fb4d76df5/fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299", size = 2894340, upload-time = "2025-09-29T21:12:43.774Z" }, + { url = "https://files.pythonhosted.org/packages/bf/a7/3b9f16e010d536ce567058b931a20b590d8f3177b2eda09edd92e392375d/fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01", size = 2375073, upload-time = "2025-09-29T21:12:46.437Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b5/e9bcf51980f98e59bb5bb7c382a63c6f6cac0eec5f67de6d8f2322382065/fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801", size = 4849758, upload-time = "2025-09-29T21:12:48.694Z" }, + { url = "https://files.pythonhosted.org/packages/e3/dc/1d2cf7d1cba82264b2f8385db3f5960e3d8ce756b4dc65b700d2c496f7e9/fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc", size = 5085598, upload-time = "2025-09-29T21:12:51.081Z" }, + { url = "https://files.pythonhosted.org/packages/5d/4d/279e28ba87fb20e0c69baf72b60bbf1c4d873af1476806a7b5f2b7fac1ff/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc", size = 4957603, upload-time = "2025-09-29T21:12:53.423Z" }, + { url = "https://files.pythonhosted.org/packages/78/d4/ff19976305e0c05aa3340c805475abb00224c954d3c65e82c0a69633d55d/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed", size = 4974184, upload-time = "2025-09-29T21:12:55.962Z" }, + { url = "https://files.pythonhosted.org/packages/63/22/8553ff6166f5cd21cfaa115aaacaa0dc73b91c079a8cfd54a482cbc0f4f5/fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259", size = 2282241, upload-time = "2025-09-29T21:12:58.179Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cb/fa7b4d148e11d5a72761a22e595344133e83a9507a4c231df972e657579b/fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c", size = 2345760, upload-time = "2025-09-29T21:13:00.375Z" }, + { url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175, upload-time = "2025-09-29T21:13:24.134Z" }, +] + +[[package]] +name = "jax" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jaxlib" }, + { name = "ml-dtypes" }, + { name = "numpy" }, + { name = "opt-einsum" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/1c/9baf805e6c969a1a7afeb37d359e8a10585e8b2621f103626998b42ae838/jax-0.8.0.tar.gz", hash = "sha256:0ea5a7be7068c25934450dfd87d7d80a18a5d30e0a53454e7aade525b23accd5", size = 2489031, upload-time = "2025-10-15T23:10:11.839Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/77/4e6c9a54247810eff8ac8a1af7dc1be0779b52df0d82f3fc8586061914f3/jax-0.8.0-py3-none-any.whl", hash = "sha256:d190158bc019756c6a0f6b3d5fc8783471fb407e6deaff559eaac60dd5ee850a", size = 2900279, upload-time = "2025-10-15T23:10:09.88Z" }, +] + +[[package]] +name = "jaxlib" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ml-dtypes" }, + { name = "numpy" }, + { name = "scipy" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/76/f11130a3a6318a50662be4ee8c7ab6e61f3f334978653243ebc9d6f5d0bb/jaxlib-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5fcf33a5639f8f164a473a9c78a1fa0b2e15ac3fcbecd6d96aa0f88bf25ea6bb", size = 54964169, upload-time = "2025-10-15T23:10:49.524Z" }, + { url = "https://files.pythonhosted.org/packages/24/2b/31ded3e83f3e198edc54519dc72cc829aa4875481ee6e19f123ef474f065/jaxlib-0.8.0-cp313-cp313-manylinux_2_27_aarch64.whl", hash = "sha256:b3eac503b90ffecc68f11fa122133eef2c62c536db28e801e436d7e7a9b67bf8", size = 73160932, upload-time = "2025-10-15T23:10:52.47Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f0/cde1d84c737bdb75712f70d69561120ce91f3f294acf2fba573c0de740b6/jaxlib-0.8.0-cp313-cp313-manylinux_2_27_x86_64.whl", hash = "sha256:66c6f576f54a63ed052f5c469bef4db723f5f050b839ec0c429573011341bd58", size = 79698354, upload-time = "2025-10-15T23:10:55.822Z" }, + { url = "https://files.pythonhosted.org/packages/f1/be/88fa119a05525f7b683588b789c0e8f51292280dfcfbf7d0193bd3f7b651/jaxlib-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:72759ebbfb40a717349f174712207d306aa28630359f05cd69b091bd4efa0603", size = 59323012, upload-time = "2025-10-15T23:10:59.475Z" }, + { url = "https://files.pythonhosted.org/packages/88/c9/2eabf3126424625dc0390a5382b8911c494b7dd8e902aa7c9d5607259664/jaxlib-0.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df2781e0fc93fb6f42111b385b90126b9571eafe0e860f033615ff7156b76817", size = 55067941, upload-time = "2025-10-15T23:11:02.235Z" }, + { url = "https://files.pythonhosted.org/packages/72/7e/1d6ef4d730b381c382847e30e39b906d5bc7ba3c13c394c0412aa0a7261e/jaxlib-0.8.0-cp313-cp313t-manylinux_2_27_aarch64.whl", hash = "sha256:7eb3be931de77bfcde27df659ada432719aa1e19a2fa5b835638e7404c74cb63", size = 73278908, upload-time = "2025-10-15T23:11:05.299Z" }, + { url = "https://files.pythonhosted.org/packages/1f/3c/d1d424e5483a8bc5eba631892c58f6c6e738844195c065bc50e6506561c0/jaxlib-0.8.0-cp313-cp313t-manylinux_2_27_x86_64.whl", hash = "sha256:accebe89a36e28306a4db3f68f527a0f87b8a0fd253b3c1556fbd24f16bec22c", size = 79805682, upload-time = "2025-10-15T23:11:08.962Z" }, + { url = "https://files.pythonhosted.org/packages/90/30/de0a3ab213a54e75207f9cb3bb48dfb87051dcee59a66955237452be1275/jaxlib-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ba7e8a2231e4138ccbd8e096debdbbcd82edc5fc1b13c66f32a51bc240651349", size = 54971716, upload-time = "2025-10-15T23:11:12.017Z" }, + { url = "https://files.pythonhosted.org/packages/83/a7/27b53c718aa5779749ebbc644d942b844f49e5527cb94d4a72119252c866/jaxlib-0.8.0-cp314-cp314-manylinux_2_27_aarch64.whl", hash = "sha256:a9bfca27ae597804db08694a2bf7e1cf7fc3fac4ac2e65ace83be8effaa927ea", size = 73181480, upload-time = "2025-10-15T23:11:15.395Z" }, + { url = "https://files.pythonhosted.org/packages/62/75/3f8fd3d40475ca13c35df382a5612a73ef0e7fa658ade521ffd6843d0573/jaxlib-0.8.0-cp314-cp314-manylinux_2_27_x86_64.whl", hash = "sha256:bd3219a4d2bfe4b72605900fde395b62126a053c0b99643eb931b7c20e577bf2", size = 79719384, upload-time = "2025-10-15T23:11:19.066Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e5/633f5513c71d52d404d17931a14fb589303c4dca9de2d66b1eb029d98ed5/jaxlib-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3320a72d532713c2a31eb20d02c342540a0dec28603a3ac2be0fc0631f086cf2", size = 61572700, upload-time = "2025-10-15T23:11:24.769Z" }, + { url = "https://files.pythonhosted.org/packages/4d/04/5e7bb66dfb5115e3753ded81354c7bbda9a45f6c0e239faec391821ce974/jaxlib-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:248f1ac3acee1fe2cc81e8a668311f3ccb8f28090404391c276869cae8a95daf", size = 55065346, upload-time = "2025-10-15T23:11:28.121Z" }, + { url = "https://files.pythonhosted.org/packages/f5/a8/dba41b8f574c188ca30866562ebf06fa0558446e11565436ead5ad4d5fe4/jaxlib-0.8.0-cp314-cp314t-manylinux_2_27_aarch64.whl", hash = "sha256:a5f0656bbbb3f135a360ce0fde55bf34faf73fbc62ab887941e85f0014b3f476", size = 73276773, upload-time = "2025-10-15T23:11:31.067Z" }, + { url = "https://files.pythonhosted.org/packages/6c/82/774ff02e014ee12925388f7a77fe9beda6a8d08537666ce6259fc810b9f6/jaxlib-0.8.0-cp314-cp314t-manylinux_2_27_x86_64.whl", hash = "sha256:61cb2fde154e5a399db2880d560e3443cfa97bda9f074b545c886232ac8fe024", size = 79805953, upload-time = "2025-10-15T23:11:34.323Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" }, + { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" }, + { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" }, + { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" }, + { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" }, + { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" }, + { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" }, + { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" }, + { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" }, + { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" }, + { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" }, + { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" }, + { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" }, + { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" }, + { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" }, + { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" }, + { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" }, + { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" }, + { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" }, + { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" }, + { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" }, + { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" }, + { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" }, + { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" }, + { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" }, + { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/e2/d2d5295be2f44c678ebaf3544ba32d20c1f9ef08c49fe47f496180e1db15/matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7", size = 34804865, upload-time = "2025-10-09T00:28:00.669Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/9c/207547916a02c78f6bdd83448d9b21afbc42f6379ed887ecf610984f3b4e/matplotlib-3.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1d9d3713a237970569156cfb4de7533b7c4eacdd61789726f444f96a0d28f57f", size = 8273212, upload-time = "2025-10-09T00:26:56.752Z" }, + { url = "https://files.pythonhosted.org/packages/bc/d0/b3d3338d467d3fc937f0bb7f256711395cae6f78e22cef0656159950adf0/matplotlib-3.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37a1fea41153dd6ee061d21ab69c9cf2cf543160b1b85d89cd3d2e2a7902ca4c", size = 8128713, upload-time = "2025-10-09T00:26:59.001Z" }, + { url = "https://files.pythonhosted.org/packages/22/ff/6425bf5c20d79aa5b959d1ce9e65f599632345391381c9a104133fe0b171/matplotlib-3.10.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3c4ea4948d93c9c29dc01c0c23eef66f2101bf75158c291b88de6525c55c3d1", size = 8698527, upload-time = "2025-10-09T00:27:00.69Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7f/ccdca06f4c2e6c7989270ed7829b8679466682f4cfc0f8c9986241c023b6/matplotlib-3.10.7-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22df30ffaa89f6643206cf13877191c63a50e8f800b038bc39bee9d2d4957632", size = 9529690, upload-time = "2025-10-09T00:27:02.664Z" }, + { url = "https://files.pythonhosted.org/packages/b8/95/b80fc2c1f269f21ff3d193ca697358e24408c33ce2b106a7438a45407b63/matplotlib-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b69676845a0a66f9da30e87f48be36734d6748024b525ec4710be40194282c84", size = 9593732, upload-time = "2025-10-09T00:27:04.653Z" }, + { url = "https://files.pythonhosted.org/packages/e1/b6/23064a96308b9aeceeffa65e96bcde459a2ea4934d311dee20afde7407a0/matplotlib-3.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:744991e0cc863dd669c8dc9136ca4e6e0082be2070b9d793cbd64bec872a6815", size = 8122727, upload-time = "2025-10-09T00:27:06.814Z" }, + { url = "https://files.pythonhosted.org/packages/b3/a6/2faaf48133b82cf3607759027f82b5c702aa99cdfcefb7f93d6ccf26a424/matplotlib-3.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:fba2974df0bf8ce3c995fa84b79cde38326e0f7b5409e7a3a481c1141340bcf7", size = 7992958, upload-time = "2025-10-09T00:27:08.567Z" }, + { url = "https://files.pythonhosted.org/packages/4a/f0/b018fed0b599bd48d84c08794cb242227fe3341952da102ee9d9682db574/matplotlib-3.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:932c55d1fa7af4423422cb6a492a31cbcbdbe68fd1a9a3f545aa5e7a143b5355", size = 8316849, upload-time = "2025-10-09T00:27:10.254Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b7/bb4f23856197659f275e11a2a164e36e65e9b48ea3e93c4ec25b4f163198/matplotlib-3.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e38c2d581d62ee729a6e144c47a71b3f42fb4187508dbbf4fe71d5612c3433b", size = 8178225, upload-time = "2025-10-09T00:27:12.241Z" }, + { url = "https://files.pythonhosted.org/packages/62/56/0600609893ff277e6f3ab3c0cef4eafa6e61006c058e84286c467223d4d5/matplotlib-3.10.7-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:786656bb13c237bbcebcd402f65f44dd61ead60ee3deb045af429d889c8dbc67", size = 8711708, upload-time = "2025-10-09T00:27:13.879Z" }, + { url = "https://files.pythonhosted.org/packages/d8/1a/6bfecb0cafe94d6658f2f1af22c43b76cf7a1c2f0dc34ef84cbb6809617e/matplotlib-3.10.7-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09d7945a70ea43bf9248f4b6582734c2fe726723204a76eca233f24cffc7ef67", size = 9541409, upload-time = "2025-10-09T00:27:15.684Z" }, + { url = "https://files.pythonhosted.org/packages/08/50/95122a407d7f2e446fd865e2388a232a23f2b81934960ea802f3171518e4/matplotlib-3.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d0b181e9fa8daf1d9f2d4c547527b167cb8838fc587deabca7b5c01f97199e84", size = 9594054, upload-time = "2025-10-09T00:27:17.547Z" }, + { url = "https://files.pythonhosted.org/packages/13/76/75b194a43b81583478a81e78a07da8d9ca6ddf50dd0a2ccabf258059481d/matplotlib-3.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:31963603041634ce1a96053047b40961f7a29eb8f9a62e80cc2c0427aa1d22a2", size = 8200100, upload-time = "2025-10-09T00:27:20.039Z" }, + { url = "https://files.pythonhosted.org/packages/f5/9e/6aefebdc9f8235c12bdeeda44cc0383d89c1e41da2c400caf3ee2073a3ce/matplotlib-3.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:aebed7b50aa6ac698c90f60f854b47e48cd2252b30510e7a1feddaf5a3f72cbf", size = 8042131, upload-time = "2025-10-09T00:27:21.608Z" }, + { url = "https://files.pythonhosted.org/packages/0d/4b/e5bc2c321b6a7e3a75638d937d19ea267c34bd5a90e12bee76c4d7c7a0d9/matplotlib-3.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d883460c43e8c6b173fef244a2341f7f7c0e9725c7fe68306e8e44ed9c8fb100", size = 8273787, upload-time = "2025-10-09T00:27:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/86/ad/6efae459c56c2fbc404da154e13e3a6039129f3c942b0152624f1c621f05/matplotlib-3.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07124afcf7a6504eafcb8ce94091c5898bbdd351519a1beb5c45f7a38c67e77f", size = 8131348, upload-time = "2025-10-09T00:27:24.926Z" }, + { url = "https://files.pythonhosted.org/packages/a6/5a/a4284d2958dee4116359cc05d7e19c057e64ece1b4ac986ab0f2f4d52d5a/matplotlib-3.10.7-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c17398b709a6cce3d9fdb1595c33e356d91c098cd9486cb2cc21ea2ea418e715", size = 9533949, upload-time = "2025-10-09T00:27:26.704Z" }, + { url = "https://files.pythonhosted.org/packages/de/ff/f3781b5057fa3786623ad8976fc9f7b0d02b2f28534751fd5a44240de4cf/matplotlib-3.10.7-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7146d64f561498764561e9cd0ed64fcf582e570fc519e6f521e2d0cfd43365e1", size = 9804247, upload-time = "2025-10-09T00:27:28.514Z" }, + { url = "https://files.pythonhosted.org/packages/47/5a/993a59facb8444efb0e197bf55f545ee449902dcee86a4dfc580c3b61314/matplotlib-3.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:90ad854c0a435da3104c01e2c6f0028d7e719b690998a2333d7218db80950722", size = 9595497, upload-time = "2025-10-09T00:27:30.418Z" }, + { url = "https://files.pythonhosted.org/packages/0d/a5/77c95aaa9bb32c345cbb49626ad8eb15550cba2e6d4c88081a6c2ac7b08d/matplotlib-3.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:4645fc5d9d20ffa3a39361fcdbcec731382763b623b72627806bf251b6388866", size = 8252732, upload-time = "2025-10-09T00:27:32.332Z" }, + { url = "https://files.pythonhosted.org/packages/74/04/45d269b4268d222390d7817dae77b159651909669a34ee9fdee336db5883/matplotlib-3.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:9257be2f2a03415f9105c486d304a321168e61ad450f6153d77c69504ad764bb", size = 8124240, upload-time = "2025-10-09T00:27:33.94Z" }, + { url = "https://files.pythonhosted.org/packages/4b/c7/ca01c607bb827158b439208c153d6f14ddb9fb640768f06f7ca3488ae67b/matplotlib-3.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1e4bbad66c177a8fdfa53972e5ef8be72a5f27e6a607cec0d8579abd0f3102b1", size = 8316938, upload-time = "2025-10-09T00:27:35.534Z" }, + { url = "https://files.pythonhosted.org/packages/84/d2/5539e66e9f56d2fdec94bb8436f5e449683b4e199bcc897c44fbe3c99e28/matplotlib-3.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d8eb7194b084b12feb19142262165832fc6ee879b945491d1c3d4660748020c4", size = 8178245, upload-time = "2025-10-09T00:27:37.334Z" }, + { url = "https://files.pythonhosted.org/packages/77/b5/e6ca22901fd3e4fe433a82e583436dd872f6c966fca7e63cf806b40356f8/matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d41379b05528091f00e1728004f9a8d7191260f3862178b88e8fd770206318", size = 9541411, upload-time = "2025-10-09T00:27:39.387Z" }, + { url = "https://files.pythonhosted.org/packages/9e/99/a4524db57cad8fee54b7237239a8f8360bfcfa3170d37c9e71c090c0f409/matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a74f79fafb2e177f240579bc83f0b60f82cc47d2f1d260f422a0627207008ca", size = 9803664, upload-time = "2025-10-09T00:27:41.492Z" }, + { url = "https://files.pythonhosted.org/packages/e6/a5/85e2edf76ea0ad4288d174926d9454ea85f3ce5390cc4e6fab196cbf250b/matplotlib-3.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:702590829c30aada1e8cef0568ddbffa77ca747b4d6e36c6d173f66e301f89cc", size = 9594066, upload-time = "2025-10-09T00:27:43.694Z" }, + { url = "https://files.pythonhosted.org/packages/39/69/9684368a314f6d83fe5c5ad2a4121a3a8e03723d2e5c8ea17b66c1bad0e7/matplotlib-3.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:f79d5de970fc90cd5591f60053aecfce1fcd736e0303d9f0bf86be649fa68fb8", size = 8342832, upload-time = "2025-10-09T00:27:45.543Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/e22e08da14bc1a0894184640d47819d2338b792732e20d292bf86e5ab785/matplotlib-3.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:cb783436e47fcf82064baca52ce748af71725d0352e1d31564cbe9c95df92b9c", size = 8172585, upload-time = "2025-10-09T00:27:47.185Z" }, +] + +[[package]] +name = "maxsmooth" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "cvxopt" }, + { name = "jax" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "progressbar" }, + { name = "scipy" }, +] + +[package.metadata] +requires-dist = [ + { name = "cvxopt", specifier = ">=1.3.2" }, + { name = "jax", specifier = ">=0.8.0" }, + { name = "matplotlib", specifier = ">=3.10.7" }, + { name = "numpy", specifier = ">=2.3.4" }, + { name = "progressbar", specifier = ">=2.5" }, + { name = "scipy", specifier = ">=1.16.3" }, +] + +[[package]] +name = "ml-dtypes" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/a7/aad060393123cfb383956dca68402aff3db1e1caffd5764887ed5153f41b/ml_dtypes-0.5.3.tar.gz", hash = "sha256:95ce33057ba4d05df50b1f3cfefab22e351868a843b3b15a46c65836283670c9", size = 692316, upload-time = "2025-07-29T18:39:19.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/87/1bcc98a66de7b2455dfb292f271452cac9edc4e870796e0d87033524d790/ml_dtypes-0.5.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5103856a225465371fe119f2fef737402b705b810bd95ad5f348e6e1a6ae21af", size = 663781, upload-time = "2025-07-29T18:38:42.984Z" }, + { url = "https://files.pythonhosted.org/packages/fd/2c/bd2a79ba7c759ee192b5601b675b180a3fd6ccf48ffa27fe1782d280f1a7/ml_dtypes-0.5.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cae435a68861660af81fa3c5af16b70ca11a17275c5b662d9c6f58294e0f113", size = 4956217, upload-time = "2025-07-29T18:38:44.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/f3/091ba84e5395d7fe5b30c081a44dec881cd84b408db1763ee50768b2ab63/ml_dtypes-0.5.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6936283b56d74fbec431ca57ce58a90a908fdbd14d4e2d22eea6d72bb208a7b7", size = 4933109, upload-time = "2025-07-29T18:38:46.405Z" }, + { url = "https://files.pythonhosted.org/packages/bc/24/054036dbe32c43295382c90a1363241684c4d6aaa1ecc3df26bd0c8d5053/ml_dtypes-0.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:d0f730a17cf4f343b2c7ad50cee3bd19e969e793d2be6ed911f43086460096e4", size = 208187, upload-time = "2025-07-29T18:38:48.24Z" }, + { url = "https://files.pythonhosted.org/packages/a6/3d/7dc3ec6794a4a9004c765e0c341e32355840b698f73fd2daff46f128afc1/ml_dtypes-0.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:2db74788fc01914a3c7f7da0763427280adfc9cd377e9604b6b64eb8097284bd", size = 161559, upload-time = "2025-07-29T18:38:50.493Z" }, + { url = "https://files.pythonhosted.org/packages/12/91/e6c7a0d67a152b9330445f9f0cf8ae6eee9b83f990b8c57fe74631e42a90/ml_dtypes-0.5.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:93c36a08a6d158db44f2eb9ce3258e53f24a9a4a695325a689494f0fdbc71770", size = 689321, upload-time = "2025-07-29T18:38:52.03Z" }, + { url = "https://files.pythonhosted.org/packages/9e/6c/b7b94b84a104a5be1883305b87d4c6bd6ae781504474b4cca067cb2340ec/ml_dtypes-0.5.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0e44a3761f64bc009d71ddb6d6c71008ba21b53ab6ee588dadab65e2fa79eafc", size = 5274495, upload-time = "2025-07-29T18:38:53.797Z" }, + { url = "https://files.pythonhosted.org/packages/5b/38/6266604dffb43378055394ea110570cf261a49876fc48f548dfe876f34cc/ml_dtypes-0.5.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdf40d2aaabd3913dec11840f0d0ebb1b93134f99af6a0a4fd88ffe924928ab4", size = 5285422, upload-time = "2025-07-29T18:38:56.603Z" }, + { url = "https://files.pythonhosted.org/packages/7c/88/8612ff177d043a474b9408f0382605d881eeb4125ba89d4d4b3286573a83/ml_dtypes-0.5.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:aec640bd94c4c85c0d11e2733bd13cbb10438fb004852996ec0efbc6cacdaf70", size = 661182, upload-time = "2025-07-29T18:38:58.414Z" }, + { url = "https://files.pythonhosted.org/packages/6f/2b/0569a5e88b29240d373e835107c94ae9256fb2191d3156b43b2601859eff/ml_dtypes-0.5.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bda32ce212baa724e03c68771e5c69f39e584ea426bfe1a701cb01508ffc7035", size = 4956187, upload-time = "2025-07-29T18:39:00.611Z" }, + { url = "https://files.pythonhosted.org/packages/51/66/273c2a06ae44562b104b61e6b14444da00061fd87652506579d7eb2c40b1/ml_dtypes-0.5.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c205cac07d24a29840c163d6469f61069ce4b065518519216297fc2f261f8db9", size = 4930911, upload-time = "2025-07-29T18:39:02.405Z" }, + { url = "https://files.pythonhosted.org/packages/93/ab/606be3e87dc0821bd360c8c1ee46108025c31a4f96942b63907bb441b87d/ml_dtypes-0.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:cd7c0bb22d4ff86d65ad61b5dd246812e8993fbc95b558553624c33e8b6903ea", size = 216664, upload-time = "2025-07-29T18:39:03.927Z" }, + { url = "https://files.pythonhosted.org/packages/30/a2/e900690ca47d01dffffd66375c5de8c4f8ced0f1ef809ccd3b25b3e6b8fa/ml_dtypes-0.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:9d55ea7f7baf2aed61bf1872116cefc9d0c3693b45cae3916897ee27ef4b835e", size = 160203, upload-time = "2025-07-29T18:39:05.671Z" }, + { url = "https://files.pythonhosted.org/packages/53/21/783dfb51f40d2660afeb9bccf3612b99f6a803d980d2a09132b0f9d216ab/ml_dtypes-0.5.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:e12e29764a0e66a7a31e9b8bf1de5cc0423ea72979f45909acd4292de834ccd3", size = 689324, upload-time = "2025-07-29T18:39:07.567Z" }, + { url = "https://files.pythonhosted.org/packages/09/f7/a82d249c711abf411ac027b7163f285487f5e615c3e0716c61033ce996ab/ml_dtypes-0.5.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19f6c3a4f635c2fc9e2aa7d91416bd7a3d649b48350c51f7f715a09370a90d93", size = 5275917, upload-time = "2025-07-29T18:39:09.339Z" }, + { url = "https://files.pythonhosted.org/packages/7f/3c/541c4b30815ab90ebfbb51df15d0b4254f2f9f1e2b4907ab229300d5e6f2/ml_dtypes-0.5.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ab039ffb40f3dc0aeeeba84fd6c3452781b5e15bef72e2d10bcb33e4bbffc39", size = 5285284, upload-time = "2025-07-29T18:39:11.532Z" }, +] + +[[package]] +name = "numpy" +version = "2.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/f4/098d2270d52b41f1bd7db9fc288aaa0400cb48c2a3e2af6fa365d9720947/numpy-2.3.4.tar.gz", hash = "sha256:a7d018bfedb375a8d979ac758b120ba846a7fe764911a64465fd87b8729f4a6a", size = 20582187, upload-time = "2025-10-15T16:18:11.77Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/7e/b72610cc91edf138bc588df5150957a4937221ca6058b825b4725c27be62/numpy-2.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c090d4860032b857d94144d1a9976b8e36709e40386db289aaf6672de2a81966", size = 20950335, upload-time = "2025-10-15T16:16:10.304Z" }, + { url = "https://files.pythonhosted.org/packages/3e/46/bdd3370dcea2f95ef14af79dbf81e6927102ddf1cc54adc0024d61252fd9/numpy-2.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a13fc473b6db0be619e45f11f9e81260f7302f8d180c49a22b6e6120022596b3", size = 14179878, upload-time = "2025-10-15T16:16:12.595Z" }, + { url = "https://files.pythonhosted.org/packages/ac/01/5a67cb785bda60f45415d09c2bc245433f1c68dd82eef9c9002c508b5a65/numpy-2.3.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:3634093d0b428e6c32c3a69b78e554f0cd20ee420dcad5a9f3b2a63762ce4197", size = 5108673, upload-time = "2025-10-15T16:16:14.877Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cd/8428e23a9fcebd33988f4cb61208fda832800ca03781f471f3727a820704/numpy-2.3.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:043885b4f7e6e232d7df4f51ffdef8c36320ee9d5f227b380ea636722c7ed12e", size = 6641438, upload-time = "2025-10-15T16:16:16.805Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d1/913fe563820f3c6b079f992458f7331278dcd7ba8427e8e745af37ddb44f/numpy-2.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ee6a571d1e4f0ea6d5f22d6e5fbd6ed1dc2b18542848e1e7301bd190500c9d7", size = 14281290, upload-time = "2025-10-15T16:16:18.764Z" }, + { url = "https://files.pythonhosted.org/packages/9e/7e/7d306ff7cb143e6d975cfa7eb98a93e73495c4deabb7d1b5ecf09ea0fd69/numpy-2.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc8a63918b04b8571789688b2780ab2b4a33ab44bfe8ccea36d3eba51228c953", size = 16636543, upload-time = "2025-10-15T16:16:21.072Z" }, + { url = "https://files.pythonhosted.org/packages/47/6a/8cfc486237e56ccfb0db234945552a557ca266f022d281a2f577b98e955c/numpy-2.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40cc556d5abbc54aabe2b1ae287042d7bdb80c08edede19f0c0afb36ae586f37", size = 16056117, upload-time = "2025-10-15T16:16:23.369Z" }, + { url = "https://files.pythonhosted.org/packages/b1/0e/42cb5e69ea901e06ce24bfcc4b5664a56f950a70efdcf221f30d9615f3f3/numpy-2.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ecb63014bb7f4ce653f8be7f1df8cbc6093a5a2811211770f6606cc92b5a78fd", size = 18577788, upload-time = "2025-10-15T16:16:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/86/92/41c3d5157d3177559ef0a35da50f0cda7fa071f4ba2306dd36818591a5bc/numpy-2.3.4-cp313-cp313-win32.whl", hash = "sha256:e8370eb6925bb8c1c4264fec52b0384b44f675f191df91cbe0140ec9f0955646", size = 6282620, upload-time = "2025-10-15T16:16:29.811Z" }, + { url = "https://files.pythonhosted.org/packages/09/97/fd421e8bc50766665ad35536c2bb4ef916533ba1fdd053a62d96cc7c8b95/numpy-2.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:56209416e81a7893036eea03abcb91c130643eb14233b2515c90dcac963fe99d", size = 12784672, upload-time = "2025-10-15T16:16:31.589Z" }, + { url = "https://files.pythonhosted.org/packages/ad/df/5474fb2f74970ca8eb978093969b125a84cc3d30e47f82191f981f13a8a0/numpy-2.3.4-cp313-cp313-win_arm64.whl", hash = "sha256:a700a4031bc0fd6936e78a752eefb79092cecad2599ea9c8039c548bc097f9bc", size = 10196702, upload-time = "2025-10-15T16:16:33.902Z" }, + { url = "https://files.pythonhosted.org/packages/11/83/66ac031464ec1767ea3ed48ce40f615eb441072945e98693bec0bcd056cc/numpy-2.3.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:86966db35c4040fdca64f0816a1c1dd8dbd027d90fca5a57e00e1ca4cd41b879", size = 21049003, upload-time = "2025-10-15T16:16:36.101Z" }, + { url = "https://files.pythonhosted.org/packages/5f/99/5b14e0e686e61371659a1d5bebd04596b1d72227ce36eed121bb0aeab798/numpy-2.3.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:838f045478638b26c375ee96ea89464d38428c69170360b23a1a50fa4baa3562", size = 14302980, upload-time = "2025-10-15T16:16:39.124Z" }, + { url = "https://files.pythonhosted.org/packages/2c/44/e9486649cd087d9fc6920e3fc3ac2aba10838d10804b1e179fb7cbc4e634/numpy-2.3.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d7315ed1dab0286adca467377c8381cd748f3dc92235f22a7dfc42745644a96a", size = 5231472, upload-time = "2025-10-15T16:16:41.168Z" }, + { url = "https://files.pythonhosted.org/packages/3e/51/902b24fa8887e5fe2063fd61b1895a476d0bbf46811ab0c7fdf4bd127345/numpy-2.3.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:84f01a4d18b2cc4ade1814a08e5f3c907b079c847051d720fad15ce37aa930b6", size = 6739342, upload-time = "2025-10-15T16:16:43.777Z" }, + { url = "https://files.pythonhosted.org/packages/34/f1/4de9586d05b1962acdcdb1dc4af6646361a643f8c864cef7c852bf509740/numpy-2.3.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:817e719a868f0dacde4abdfc5c1910b301877970195db9ab6a5e2c4bd5b121f7", size = 14354338, upload-time = "2025-10-15T16:16:46.081Z" }, + { url = "https://files.pythonhosted.org/packages/1f/06/1c16103b425de7969d5a76bdf5ada0804b476fed05d5f9e17b777f1cbefd/numpy-2.3.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85e071da78d92a214212cacea81c6da557cab307f2c34b5f85b628e94803f9c0", size = 16702392, upload-time = "2025-10-15T16:16:48.455Z" }, + { url = "https://files.pythonhosted.org/packages/34/b2/65f4dc1b89b5322093572b6e55161bb42e3e0487067af73627f795cc9d47/numpy-2.3.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2ec646892819370cf3558f518797f16597b4e4669894a2ba712caccc9da53f1f", size = 16134998, upload-time = "2025-10-15T16:16:51.114Z" }, + { url = "https://files.pythonhosted.org/packages/d4/11/94ec578896cdb973aaf56425d6c7f2aff4186a5c00fac15ff2ec46998b46/numpy-2.3.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:035796aaaddfe2f9664b9a9372f089cfc88bd795a67bd1bfe15e6e770934cf64", size = 18651574, upload-time = "2025-10-15T16:16:53.429Z" }, + { url = "https://files.pythonhosted.org/packages/62/b7/7efa763ab33dbccf56dade36938a77345ce8e8192d6b39e470ca25ff3cd0/numpy-2.3.4-cp313-cp313t-win32.whl", hash = "sha256:fea80f4f4cf83b54c3a051f2f727870ee51e22f0248d3114b8e755d160b38cfb", size = 6413135, upload-time = "2025-10-15T16:16:55.992Z" }, + { url = "https://files.pythonhosted.org/packages/43/70/aba4c38e8400abcc2f345e13d972fb36c26409b3e644366db7649015f291/numpy-2.3.4-cp313-cp313t-win_amd64.whl", hash = "sha256:15eea9f306b98e0be91eb344a94c0e630689ef302e10c2ce5f7e11905c704f9c", size = 12928582, upload-time = "2025-10-15T16:16:57.943Z" }, + { url = "https://files.pythonhosted.org/packages/67/63/871fad5f0073fc00fbbdd7232962ea1ac40eeaae2bba66c76214f7954236/numpy-2.3.4-cp313-cp313t-win_arm64.whl", hash = "sha256:b6c231c9c2fadbae4011ca5e7e83e12dc4a5072f1a1d85a0a7b3ed754d145a40", size = 10266691, upload-time = "2025-10-15T16:17:00.048Z" }, + { url = "https://files.pythonhosted.org/packages/72/71/ae6170143c115732470ae3a2d01512870dd16e0953f8a6dc89525696069b/numpy-2.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:81c3e6d8c97295a7360d367f9f8553973651b76907988bb6066376bc2252f24e", size = 20955580, upload-time = "2025-10-15T16:17:02.509Z" }, + { url = "https://files.pythonhosted.org/packages/af/39/4be9222ffd6ca8a30eda033d5f753276a9c3426c397bb137d8e19dedd200/numpy-2.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7c26b0b2bf58009ed1f38a641f3db4be8d960a417ca96d14e5b06df1506d41ff", size = 14188056, upload-time = "2025-10-15T16:17:04.873Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3d/d85f6700d0a4aa4f9491030e1021c2b2b7421b2b38d01acd16734a2bfdc7/numpy-2.3.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:62b2198c438058a20b6704351b35a1d7db881812d8512d67a69c9de1f18ca05f", size = 5116555, upload-time = "2025-10-15T16:17:07.499Z" }, + { url = "https://files.pythonhosted.org/packages/bf/04/82c1467d86f47eee8a19a464c92f90a9bb68ccf14a54c5224d7031241ffb/numpy-2.3.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:9d729d60f8d53a7361707f4b68a9663c968882dd4f09e0d58c044c8bf5faee7b", size = 6643581, upload-time = "2025-10-15T16:17:09.774Z" }, + { url = "https://files.pythonhosted.org/packages/0c/d3/c79841741b837e293f48bd7db89d0ac7a4f2503b382b78a790ef1dc778a5/numpy-2.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd0c630cf256b0a7fd9d0a11c9413b42fef5101219ce6ed5a09624f5a65392c7", size = 14299186, upload-time = "2025-10-15T16:17:11.937Z" }, + { url = "https://files.pythonhosted.org/packages/e8/7e/4a14a769741fbf237eec5a12a2cbc7a4c4e061852b6533bcb9e9a796c908/numpy-2.3.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5e081bc082825f8b139f9e9fe42942cb4054524598aaeb177ff476cc76d09d2", size = 16638601, upload-time = "2025-10-15T16:17:14.391Z" }, + { url = "https://files.pythonhosted.org/packages/93/87/1c1de269f002ff0a41173fe01dcc925f4ecff59264cd8f96cf3b60d12c9b/numpy-2.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15fb27364ed84114438fff8aaf998c9e19adbeba08c0b75409f8c452a8692c52", size = 16074219, upload-time = "2025-10-15T16:17:17.058Z" }, + { url = "https://files.pythonhosted.org/packages/cd/28/18f72ee77408e40a76d691001ae599e712ca2a47ddd2c4f695b16c65f077/numpy-2.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:85d9fb2d8cd998c84d13a79a09cc0c1091648e848e4e6249b0ccd7f6b487fa26", size = 18576702, upload-time = "2025-10-15T16:17:19.379Z" }, + { url = "https://files.pythonhosted.org/packages/c3/76/95650169b465ececa8cf4b2e8f6df255d4bf662775e797ade2025cc51ae6/numpy-2.3.4-cp314-cp314-win32.whl", hash = "sha256:e73d63fd04e3a9d6bc187f5455d81abfad05660b212c8804bf3b407e984cd2bc", size = 6337136, upload-time = "2025-10-15T16:17:22.886Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/a231a5c43ede5d6f77ba4a91e915a87dea4aeea76560ba4d2bf185c683f0/numpy-2.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:3da3491cee49cf16157e70f607c03a217ea6647b1cea4819c4f48e53d49139b9", size = 12920542, upload-time = "2025-10-15T16:17:24.783Z" }, + { url = "https://files.pythonhosted.org/packages/0d/0c/ae9434a888f717c5ed2ff2393b3f344f0ff6f1c793519fa0c540461dc530/numpy-2.3.4-cp314-cp314-win_arm64.whl", hash = "sha256:6d9cd732068e8288dbe2717177320723ccec4fb064123f0caf9bbd90ab5be868", size = 10480213, upload-time = "2025-10-15T16:17:26.935Z" }, + { url = "https://files.pythonhosted.org/packages/83/4b/c4a5f0841f92536f6b9592694a5b5f68c9ab37b775ff342649eadf9055d3/numpy-2.3.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:22758999b256b595cf0b1d102b133bb61866ba5ceecf15f759623b64c020c9ec", size = 21052280, upload-time = "2025-10-15T16:17:29.638Z" }, + { url = "https://files.pythonhosted.org/packages/3e/80/90308845fc93b984d2cc96d83e2324ce8ad1fd6efea81b324cba4b673854/numpy-2.3.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9cb177bc55b010b19798dc5497d540dea67fd13a8d9e882b2dae71de0cf09eb3", size = 14302930, upload-time = "2025-10-15T16:17:32.384Z" }, + { url = "https://files.pythonhosted.org/packages/3d/4e/07439f22f2a3b247cec4d63a713faae55e1141a36e77fb212881f7cda3fb/numpy-2.3.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0f2bcc76f1e05e5ab58893407c63d90b2029908fa41f9f1cc51eecce936c3365", size = 5231504, upload-time = "2025-10-15T16:17:34.515Z" }, + { url = "https://files.pythonhosted.org/packages/ab/de/1e11f2547e2fe3d00482b19721855348b94ada8359aef5d40dd57bfae9df/numpy-2.3.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dc20bde86802df2ed8397a08d793da0ad7a5fd4ea3ac85d757bf5dd4ad7c252", size = 6739405, upload-time = "2025-10-15T16:17:36.128Z" }, + { url = "https://files.pythonhosted.org/packages/3b/40/8cd57393a26cebe2e923005db5134a946c62fa56a1087dc7c478f3e30837/numpy-2.3.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e199c087e2aa71c8f9ce1cb7a8e10677dc12457e7cc1be4798632da37c3e86e", size = 14354866, upload-time = "2025-10-15T16:17:38.884Z" }, + { url = "https://files.pythonhosted.org/packages/93/39/5b3510f023f96874ee6fea2e40dfa99313a00bf3ab779f3c92978f34aace/numpy-2.3.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85597b2d25ddf655495e2363fe044b0ae999b75bc4d630dc0d886484b03a5eb0", size = 16703296, upload-time = "2025-10-15T16:17:41.564Z" }, + { url = "https://files.pythonhosted.org/packages/41/0d/19bb163617c8045209c1996c4e427bccbc4bbff1e2c711f39203c8ddbb4a/numpy-2.3.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04a69abe45b49c5955923cf2c407843d1c85013b424ae8a560bba16c92fe44a0", size = 16136046, upload-time = "2025-10-15T16:17:43.901Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c1/6dba12fdf68b02a21ac411c9df19afa66bed2540f467150ca64d246b463d/numpy-2.3.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e1708fac43ef8b419c975926ce1eaf793b0c13b7356cfab6ab0dc34c0a02ac0f", size = 18652691, upload-time = "2025-10-15T16:17:46.247Z" }, + { url = "https://files.pythonhosted.org/packages/f8/73/f85056701dbbbb910c51d846c58d29fd46b30eecd2b6ba760fc8b8a1641b/numpy-2.3.4-cp314-cp314t-win32.whl", hash = "sha256:863e3b5f4d9915aaf1b8ec79ae560ad21f0b8d5e3adc31e73126491bb86dee1d", size = 6485782, upload-time = "2025-10-15T16:17:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/17/90/28fa6f9865181cb817c2471ee65678afa8a7e2a1fb16141473d5fa6bacc3/numpy-2.3.4-cp314-cp314t-win_amd64.whl", hash = "sha256:962064de37b9aef801d33bc579690f8bfe6c5e70e29b61783f60bcba838a14d6", size = 13113301, upload-time = "2025-10-15T16:17:50.938Z" }, + { url = "https://files.pythonhosted.org/packages/54/23/08c002201a8e7e1f9afba93b97deceb813252d9cfd0d3351caed123dcf97/numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29", size = 10547532, upload-time = "2025-10-15T16:17:53.48Z" }, +] + +[[package]] +name = "opt-einsum" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004, upload-time = "2024-09-26T14:33:24.483Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932, upload-time = "2024-09-26T14:33:23.039Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pillow" +version = "12.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493, upload-time = "2025-10-15T18:22:25.758Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461, upload-time = "2025-10-15T18:22:27.286Z" }, + { url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912, upload-time = "2025-10-15T18:22:28.751Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132, upload-time = "2025-10-15T18:22:30.641Z" }, + { url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099, upload-time = "2025-10-15T18:22:32.73Z" }, + { url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808, upload-time = "2025-10-15T18:22:34.337Z" }, + { url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804, upload-time = "2025-10-15T18:22:36.402Z" }, + { url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553, upload-time = "2025-10-15T18:22:38.066Z" }, + { url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729, upload-time = "2025-10-15T18:22:39.769Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789, upload-time = "2025-10-15T18:22:41.437Z" }, + { url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917, upload-time = "2025-10-15T18:22:43.152Z" }, + { url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391, upload-time = "2025-10-15T18:22:44.753Z" }, + { url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477, upload-time = "2025-10-15T18:22:46.838Z" }, + { url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918, upload-time = "2025-10-15T18:22:48.399Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406, upload-time = "2025-10-15T18:22:49.905Z" }, + { url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218, upload-time = "2025-10-15T18:22:51.587Z" }, + { url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564, upload-time = "2025-10-15T18:22:53.215Z" }, + { url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260, upload-time = "2025-10-15T18:22:54.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248, upload-time = "2025-10-15T18:22:56.605Z" }, + { url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043, upload-time = "2025-10-15T18:22:58.53Z" }, + { url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915, upload-time = "2025-10-15T18:23:00.582Z" }, + { url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998, upload-time = "2025-10-15T18:23:02.627Z" }, + { url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201, upload-time = "2025-10-15T18:23:04.709Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165, upload-time = "2025-10-15T18:23:06.46Z" }, + { url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834, upload-time = "2025-10-15T18:23:08.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/2a/9a8c6ba2c2c07b71bec92cf63e03370ca5e5f5c5b119b742bcc0cde3f9c5/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9", size = 4045531, upload-time = "2025-10-15T18:23:10.121Z" }, + { url = "https://files.pythonhosted.org/packages/84/54/836fdbf1bfb3d66a59f0189ff0b9f5f666cee09c6188309300df04ad71fa/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2", size = 4120554, upload-time = "2025-10-15T18:23:12.14Z" }, + { url = "https://files.pythonhosted.org/packages/0d/cd/16aec9f0da4793e98e6b54778a5fbce4f375c6646fe662e80600b8797379/pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a", size = 3576812, upload-time = "2025-10-15T18:23:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b7/13957fda356dc46339298b351cae0d327704986337c3c69bb54628c88155/pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b", size = 5252689, upload-time = "2025-10-15T18:23:15.562Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f5/eae31a306341d8f331f43edb2e9122c7661b975433de5e447939ae61c5da/pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad", size = 4650186, upload-time = "2025-10-15T18:23:17.379Z" }, + { url = "https://files.pythonhosted.org/packages/86/62/2a88339aa40c4c77e79108facbd307d6091e2c0eb5b8d3cf4977cfca2fe6/pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01", size = 6230308, upload-time = "2025-10-15T18:23:18.971Z" }, + { url = "https://files.pythonhosted.org/packages/c7/33/5425a8992bcb32d1cb9fa3dd39a89e613d09a22f2c8083b7bf43c455f760/pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c", size = 8039222, upload-time = "2025-10-15T18:23:20.909Z" }, + { url = "https://files.pythonhosted.org/packages/d8/61/3f5d3b35c5728f37953d3eec5b5f3e77111949523bd2dd7f31a851e50690/pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e", size = 6346657, upload-time = "2025-10-15T18:23:23.077Z" }, + { url = "https://files.pythonhosted.org/packages/3a/be/ee90a3d79271227e0f0a33c453531efd6ed14b2e708596ba5dd9be948da3/pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e", size = 7038482, upload-time = "2025-10-15T18:23:25.005Z" }, + { url = "https://files.pythonhosted.org/packages/44/34/a16b6a4d1ad727de390e9bd9f19f5f669e079e5826ec0f329010ddea492f/pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9", size = 6461416, upload-time = "2025-10-15T18:23:27.009Z" }, + { url = "https://files.pythonhosted.org/packages/b6/39/1aa5850d2ade7d7ba9f54e4e4c17077244ff7a2d9e25998c38a29749eb3f/pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab", size = 7131584, upload-time = "2025-10-15T18:23:29.752Z" }, + { url = "https://files.pythonhosted.org/packages/bf/db/4fae862f8fad0167073a7733973bfa955f47e2cac3dc3e3e6257d10fab4a/pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b", size = 6400621, upload-time = "2025-10-15T18:23:32.06Z" }, + { url = "https://files.pythonhosted.org/packages/2b/24/b350c31543fb0107ab2599464d7e28e6f856027aadda995022e695313d94/pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b", size = 7142916, upload-time = "2025-10-15T18:23:34.71Z" }, + { url = "https://files.pythonhosted.org/packages/0f/9b/0ba5a6fd9351793996ef7487c4fdbde8d3f5f75dbedc093bb598648fddf0/pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0", size = 2523836, upload-time = "2025-10-15T18:23:36.967Z" }, + { url = "https://files.pythonhosted.org/packages/f5/7a/ceee0840aebc579af529b523d530840338ecf63992395842e54edc805987/pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6", size = 5255092, upload-time = "2025-10-15T18:23:38.573Z" }, + { url = "https://files.pythonhosted.org/packages/44/76/20776057b4bfd1aef4eeca992ebde0f53a4dce874f3ae693d0ec90a4f79b/pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6", size = 4653158, upload-time = "2025-10-15T18:23:40.238Z" }, + { url = "https://files.pythonhosted.org/packages/82/3f/d9ff92ace07be8836b4e7e87e6a4c7a8318d47c2f1463ffcf121fc57d9cb/pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1", size = 6267882, upload-time = "2025-10-15T18:23:42.434Z" }, + { url = "https://files.pythonhosted.org/packages/9f/7a/4f7ff87f00d3ad33ba21af78bfcd2f032107710baf8280e3722ceec28cda/pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e", size = 8071001, upload-time = "2025-10-15T18:23:44.29Z" }, + { url = "https://files.pythonhosted.org/packages/75/87/fcea108944a52dad8cca0715ae6247e271eb80459364a98518f1e4f480c1/pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca", size = 6380146, upload-time = "2025-10-15T18:23:46.065Z" }, + { url = "https://files.pythonhosted.org/packages/91/52/0d31b5e571ef5fd111d2978b84603fce26aba1b6092f28e941cb46570745/pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925", size = 7067344, upload-time = "2025-10-15T18:23:47.898Z" }, + { url = "https://files.pythonhosted.org/packages/7b/f4/2dd3d721f875f928d48e83bb30a434dee75a2531bca839bb996bb0aa5a91/pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8", size = 6491864, upload-time = "2025-10-15T18:23:49.607Z" }, + { url = "https://files.pythonhosted.org/packages/30/4b/667dfcf3d61fc309ba5a15b141845cece5915e39b99c1ceab0f34bf1d124/pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4", size = 7158911, upload-time = "2025-10-15T18:23:51.351Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045, upload-time = "2025-10-15T18:23:53.177Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282, upload-time = "2025-10-15T18:23:55.316Z" }, + { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" }, +] + +[[package]] +name = "progressbar" +version = "2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/a6/b8e451f6cff1c99b4747a2f7235aa904d2d49e8e1464e0b798272aa84358/progressbar-2.5.tar.gz", hash = "sha256:5d81cb529da2e223b53962afd6c8ca0f05c6670e40309a7219eacc36af9b6c63", size = 10046, upload-time = "2018-06-29T02:32:00.222Z" } + +[[package]] +name = "pyparsing" +version = "3.2.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "scipy" +version = "1.16.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, + { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, + { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, + { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, + { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, + { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, + { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, + { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, + { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, + { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, + { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, + { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, + { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, + { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, + { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, + { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, + { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, + { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, + { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, + { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, + { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, + { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, + { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, + { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, + { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, + { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, + { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, + { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] From 407ca561057ad9951cd1e0ea2439f10de341a8e5 Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 12:29:38 +0000 Subject: [PATCH 03/52] jit compliant versions of funcitons --- maxsmooth/Models.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/maxsmooth/Models.py b/maxsmooth/Models.py index ce0f2ce..673bffe 100755 --- a/maxsmooth/Models.py +++ b/maxsmooth/Models.py @@ -2,37 +2,43 @@ import jax @jax.jit -def normalised_polynomial(x, y, N, pivot_point, params): - y_sum = y[pivot_point]*jnp.sum(jnp.array([ - params[i]*(x/x[pivot_point])**i for i in range(N)]), axis=0) +def normalised_polynomial(x, y, pivot_point, params): + i = jnp.arange(params.shape[0]) + powers = (x / x[pivot_point])[None, :] ** i[:, None] + y_sum = y[pivot_point] * jnp.sum(params[:, None] * powers, axis=0) return y_sum @jax.jit -def polynomial(x, y, N, pivot_point, params): - y_sum = jnp.sum(jnp.array([ - params[i]*(x)**i for i in range(N)]), axis=0) +def polynomial(x, y, pivot_point, params): + i = jnp.arange(params.shape[0]) + powers = x[None, :] ** i[:, None] + y_sum = jnp.sum(params[:, None] * powers, axis=0) return y_sum @jax.jit -def loglog_polynomial(x, y, N, pivot_point, params): - y_sum = 10**(jnp.sum(jnp.array([ - params[i]*jnp.log10(x)**i for i in range(N)]), axis=0)) +def loglog_polynomial(x, y, pivot_point, params): + i = jnp.arange(params.shape[0]) + powers = jnp.log10(x)[None, :] ** i[:, None] + y_sum = 10**jnp.sum(params[:, None] * powers, axis=0) return y_sum @jax.jit -def exponential(x, y, N, pivot_point, params): - y_sum = y[pivot_point]*jnp.sum(jnp.array([ - params[i]*jnp.exp(-i*x/x[pivot_point]) for i in range(N)]), axis=0) +def exponential(x, y, pivot_point, params): + i = jnp.arange(params.shape[0]) + powers = jnp.exp(-i[:, None] * x[None, :] / x[pivot_point]) + y_sum = y[pivot_point] * jnp.sum(params[:, None] * powers, axis=0) return y_sum @jax.jit -def log_polynomial(x, y, N, pivot_point, params): - y_sum = jnp.sum(jnp.array([ - params[i]*jnp.log10(x/x[pivot_point])**i for i in range(N)]), axis=0) +def log_polynomial(x, y, pivot_point, params): + i = jnp.arange(params.shape[0]) + powers = jnp.log10(x / x[pivot_point])[None, :] ** i[:, None] + y_sum = jnp.sum(params[:, None] * powers, axis=0) return y_sum @jax.jit -def difference_polynomial(x, y, N, pivot_point, params): - y_sum = jnp.sum(jnp.array([ - params[i]*(x - x[pivot_point])**i for i in range(N)]), axis=0) +def difference_polynomial(x, y, pivot_point, params): + i = jnp.arange(params.shape[0]) + powers = (x - x[pivot_point])[None, :] ** i[:, None] + y_sum = jnp.sum(params[:, None] * powers, axis=0) return y_sum From b9fc5250e8d203944ec45e2f7d37f5a8bf3fd645 Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 12:30:04 +0000 Subject: [PATCH 04/52] renaming file caps looks horrible --- maxsmooth/{Models.py => models.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename maxsmooth/{Models.py => models.py} (100%) diff --git a/maxsmooth/Models.py b/maxsmooth/models.py similarity index 100% rename from maxsmooth/Models.py rename to maxsmooth/models.py From 65cb84e426f4ff739546e0cc362d6599a7674817 Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 13:02:44 +0000 Subject: [PATCH 05/52] function to generate functions to evaluate derivatives up to m --- maxsmooth/derivatives.py | 170 ++------------------------------------- maxsmooth/models.py | 37 ++++----- 2 files changed, 26 insertions(+), 181 deletions(-) diff --git a/maxsmooth/derivatives.py b/maxsmooth/derivatives.py index b6b99a3..9c4bda2 100755 --- a/maxsmooth/derivatives.py +++ b/maxsmooth/derivatives.py @@ -1,165 +1,9 @@ -import numpy as np -from scipy.special import lpmv +import jax -class derivative_class(object): - def __init__( - self, x, y, params, N, pivot_point, model_type, zero_crossings, - constraints, new_basis, **kwargs): - self.x = x - self.y = y - self.N = N - self.params = params - self.pivot_point = pivot_point - self.model_type = model_type - self.zero_crossings = zero_crossings - self.derivatives_function = new_basis['derivatives_function'] - self.args = new_basis['args'] - self.constraints = constraints - - self.call_type = kwargs.pop('call_type', 'checking') - - self.derivatives, self.pass_fail, self.zc_dict = \ - self.derivatives_func() - - def derivatives_func(self): - - def mth_order_derivatives(m): - if self.derivatives_function is None: - if np.any(self.model_type != ['legendre', 'exponential']): - mth_order_derivative = [] - for i in range(self.N-m): - if self.model_type == 'normalised_polynomial': - mth_order_derivative_term = ( - self.y[self.pivot_point] / - self.x[self.pivot_point]) * \ - np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - self.params[int(m)+i]*(self.x)**i / \ - (self.x[self.pivot_point])**(i+1) - mth_order_derivative.append( - mth_order_derivative_term) - if self.model_type == 'polynomial': - mth_order_derivative_term = \ - np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - self.params[int(m)+i]*(self.x)**i - mth_order_derivative.append( - mth_order_derivative_term) - if self.model_type == 'log_polynomial': - mth_order_derivative_term = \ - np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - self.params[int(m) + i] * \ - np.log10(self.x/self.x[self.pivot_point])**i - mth_order_derivative.append( - mth_order_derivative_term) - if self.model_type == 'loglog_polynomial': - mth_order_derivative_term = \ - np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - self.params[int(m)+i]*np.log10(self.x)**i - mth_order_derivative.append( - mth_order_derivative_term) - if self.model_type == 'difference_polynomial': - mth_order_derivative_term = \ - np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - self.params[int(m)+i] * \ - (self.x-self.x[self.pivot_point])**i - mth_order_derivative.append( - mth_order_derivative_term) - - if self.derivatives_function is not None: - if self.args is None: - derivatives = \ - self.derivatives_function( - m, self.x, self.y, self.N, self.pivot_point, - self.params) - if self.args is not None: - derivatives = \ - self.derivatives_function( - m, self.x, self.y, self.N, self.pivot_point, - self.params, *self.args) - mth_order_derivative = derivatives - - if self.model_type == 'legendre': - interval = np.linspace(-0.999, 0.999, len(self.x)) - alps = [] - for i in range(self.N): - alps.append(lpmv(m, i, interval)) - alps = np.array(alps) - derivatives = [] - for h in range(len(alps)): - derivatives.append( - ((alps[h, :]*(-1)**(m))/(1-interval**2)**(m/2)) - * self.params[h, 0]) - mth_order_derivative = np.array(derivatives) - if self.model_type == 'exponential': - derivatives = np.empty([self.N, len(self.x)]) - for i in range(self.N): - for h in range(len(self.x)): - derivatives[i, h] = \ - self.y[self.pivot_point] * ( - self.params[i] * - np.exp(-i * self.x[h]/self.x[self.pivot_point])) \ - * (-i/self.x[self.pivot_point])**m - mth_order_derivative = np.array(derivatives) - - if type(mth_order_derivative) == list: - mth_order_derivative = np.array(mth_order_derivative) - if mth_order_derivative.shape == (len(self.x), self.N): - mth_order_derivative = mth_order_derivative.sum(axis=1) - else: - mth_order_derivative = mth_order_derivative.sum(axis=0) - - return mth_order_derivative - - m = np.arange(0, self.N, 1) - derivatives = [] - zc_derivatives = [] - zc_orders = [] - for i in range(len(m)): - if m[i] < self.constraints: - zc_orders.append(m[i]) - zc_derivatives.append(mth_order_derivatives(m[i])) - if m[i] >= self.constraints: - if self.zero_crossings is not None: - if m[i] not in set(self.zero_crossings): - derivatives.append(mth_order_derivatives(m[i])) - if m[i] in set(self.zero_crossings): - zc_orders.append(m[i]) - zc_derivatives.append(mth_order_derivatives(m[i])) - else: - derivatives.append(mth_order_derivatives(m[i])) - derivatives = np.array(derivatives) - - zc_derivatives = np.array(zc_derivatives) - zc_orders = np.array(zc_orders) - - # Check constrained derivatives - pass_fail = [] - for i in range(derivatives.shape[0]): - if np.all(derivatives[i, :] >= -1e-6) or \ - np.all(derivatives[i, :] <= 1e-6): - pass_fail.append(1) - else: - pass_fail.append(0) - pass_fail = np.array(pass_fail) - - zc_dict = {} - for i in range(zc_derivatives.shape[0]): - if np.all(zc_derivatives[i, :] >= -1e-6) or \ - np.all(zc_derivatives[i, :] <= 1e-6): - zc_dict[str(zc_orders[i])] = 1 - else: - zc_dict[str(zc_orders[i])] = 0 - - if self.call_type == 'checking': - if np.any(pass_fail == 0): - print('Pass or fail', pass_fail) - raise Exception( - '"Condition Violated" Derivatives feature' + - ' crossing points.') - - return derivatives, pass_fail, zc_dict +# function to generate derivatives +def make_derivative_functions(f, max_order): + derivs = [f] + for n in range(1, max_order): + derivs.append(jax.grad(derivs[-1], argnums=0)) + return derivs \ No newline at end of file diff --git a/maxsmooth/models.py b/maxsmooth/models.py index 673bffe..59e4cfd 100755 --- a/maxsmooth/models.py +++ b/maxsmooth/models.py @@ -2,43 +2,44 @@ import jax @jax.jit -def normalised_polynomial(x, y, pivot_point, params): +def normalised_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = (x / x[pivot_point])[None, :] ** i[:, None] - y_sum = y[pivot_point] * jnp.sum(params[:, None] * powers, axis=0) + powers = (x / norm_x) ** i + y_sum = norm_y * jnp.sum(params * powers, axis=0) return y_sum @jax.jit -def polynomial(x, y, pivot_point, params): +def polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = x[None, :] ** i[:, None] - y_sum = jnp.sum(params[:, None] * powers, axis=0) + powers = x ** i + y_sum = jnp.sum(params * powers, axis=0) return y_sum @jax.jit -def loglog_polynomial(x, y, pivot_point, params): +def loglog_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = jnp.log10(x)[None, :] ** i[:, None] - y_sum = 10**jnp.sum(params[:, None] * powers, axis=0) + powers = jnp.log10(x) ** i + y_sum = 10**jnp.sum(params * powers, axis=0) return y_sum @jax.jit -def exponential(x, y, pivot_point, params): +def exponential(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = jnp.exp(-i[:, None] * x[None, :] / x[pivot_point]) - y_sum = y[pivot_point] * jnp.sum(params[:, None] * powers, axis=0) + x = x + 1e-10 # avoid division by zero + powers = jnp.exp(-i * x / norm_x) + y_sum = norm_y * jnp.sum(params * powers, axis=0) return y_sum @jax.jit -def log_polynomial(x, y, pivot_point, params): +def log_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = jnp.log10(x / x[pivot_point])[None, :] ** i[:, None] - y_sum = jnp.sum(params[:, None] * powers, axis=0) + powers = jnp.log10(x / norm_x) ** i + y_sum = jnp.sum(params * powers, axis=0) return y_sum @jax.jit -def difference_polynomial(x, y, pivot_point, params): +def difference_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = (x - x[pivot_point])[None, :] ** i[:, None] - y_sum = jnp.sum(params[:, None] * powers, axis=0) + powers = (x - norm_x) ** i + y_sum = jnp.sum(params * powers, axis=0) return y_sum From e6615c5f974de901211a1291f3ff1321b445f5c8 Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 13:50:07 +0000 Subject: [PATCH 06/52] get the prefactors on the derivatives --- maxsmooth/derivatives.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/maxsmooth/derivatives.py b/maxsmooth/derivatives.py index 9c4bda2..2222ae2 100755 --- a/maxsmooth/derivatives.py +++ b/maxsmooth/derivatives.py @@ -1,9 +1,24 @@ import jax - # function to generate derivatives def make_derivative_functions(f, max_order): derivs = [f] for n in range(1, max_order): derivs.append(jax.grad(derivs[-1], argnums=0)) - return derivs \ No newline at end of file + return derivs + +def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): + """Return list of derivative matrices G[m] mapping params -> m-th derivative at all x.""" + + Gs = [] + for m in range(max_order): + df_dx = f + # take m-th derivative w.r.t x + for _ in range(m): + prev_df_dx = df_dx + def df_dx(xi, norm_x, norm_y, p, prev_df_dx=prev_df_dx): + return jax.grad(prev_df_dx, argnums=0)(xi, norm_x, norm_y, p) + # Jacobian w.r.t params + Gm = jax.vmap(lambda xi: jax.jacobian(df_dx, argnums=3)(xi, norm_x, norm_y, params))(x) + Gs.append(Gm) + return Gs \ No newline at end of file From b61bb9bb81f4f3e3e544f845a72964d6404f709b Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 14:02:45 +0000 Subject: [PATCH 07/52] adding some notes --- maxsmooth/derivatives.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/maxsmooth/derivatives.py b/maxsmooth/derivatives.py index 2222ae2..d2cec14 100755 --- a/maxsmooth/derivatives.py +++ b/maxsmooth/derivatives.py @@ -8,7 +8,13 @@ def make_derivative_functions(f, max_order): return derivs def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): - """Return list of derivative matrices G[m] mapping params -> m-th derivative at all x.""" + """ + Return list of derivative matrices G[m] mapping params -> m-th derivative at all x. + + Taking the derivative of the function w.r.t x and then taking the Jacobian w.r.t params + for each order up to max_order gives the prefactor matrices Gs which are + needed for G . params = d^m f / dx^m < h. + """ Gs = [] for m in range(max_order): From f7251db271792d93f4486ffec447c6c5b503ad2c Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 14:02:59 +0000 Subject: [PATCH 08/52] seperate funcitons to get basis --- maxsmooth/models.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/maxsmooth/models.py b/maxsmooth/models.py index 59e4cfd..2fef48a 100755 --- a/maxsmooth/models.py +++ b/maxsmooth/models.py @@ -8,6 +8,12 @@ def normalised_polynomial(x, norm_x, norm_y, params): y_sum = norm_y * jnp.sum(params * powers, axis=0) return y_sum +@jax.jit +def normalised_polynomial_basis(x, norm_x, order): + i = jnp.arange(order) + powers = (x / norm_x) ** i + return powers + @jax.jit def polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) @@ -15,6 +21,12 @@ def polynomial(x, norm_x, norm_y, params): y_sum = jnp.sum(params * powers, axis=0) return y_sum +@jax.jit +def polynomial_basis(x, order): + i = jnp.arange(order) + powers = x ** i + return powers + @jax.jit def loglog_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) @@ -22,14 +34,25 @@ def loglog_polynomial(x, norm_x, norm_y, params): y_sum = 10**jnp.sum(params * powers, axis=0) return y_sum +@jax.jit +def loglog_polynomial_basis(x, order): + i = jnp.arange(order) + powers = jnp.log10(x) ** i + return powers + @jax.jit def exponential(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - x = x + 1e-10 # avoid division by zero powers = jnp.exp(-i * x / norm_x) y_sum = norm_y * jnp.sum(params * powers, axis=0) return y_sum +@jax.jit +def exponential_basis(x, norm_x, order): + i = jnp.arange(order) + powers = jnp.exp(-i * x / norm_x) + return powers + @jax.jit def log_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) @@ -37,9 +60,21 @@ def log_polynomial(x, norm_x, norm_y, params): y_sum = jnp.sum(params * powers, axis=0) return y_sum +@jax.jit +def log_polynomial_basis(x, norm_x, order): + i = jnp.arange(order) + powers = jnp.log10(x / norm_x) ** i + return powers + @jax.jit def difference_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) powers = (x - norm_x) ** i y_sum = jnp.sum(params * powers, axis=0) return y_sum + +@jax.jit +def difference_polynomial_basis(x, norm_x, order): + i = jnp.arange(order) + powers = (x - norm_x) ** i + return powers \ No newline at end of file From c24498064e0192c15e9cf1405f015cc68cbf3710 Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 4 Nov 2025 15:37:27 +0000 Subject: [PATCH 09/52] trying to get some form of qp working --- maxsmooth/derivatives.py | 22 +++++++++----- maxsmooth/models.py | 28 ++++++++--------- pyproject.toml | 1 + qptesting.py | 66 ++++++++++++++++++++++++++++++++++++++++ uv.lock | 17 +++++++++++ 5 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 qptesting.py diff --git a/maxsmooth/derivatives.py b/maxsmooth/derivatives.py index d2cec14..1aedb7a 100755 --- a/maxsmooth/derivatives.py +++ b/maxsmooth/derivatives.py @@ -7,14 +7,7 @@ def make_derivative_functions(f, max_order): derivs.append(jax.grad(derivs[-1], argnums=0)) return derivs -def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): - """ - Return list of derivative matrices G[m] mapping params -> m-th derivative at all x. - - Taking the derivative of the function w.r.t x and then taking the Jacobian w.r.t params - for each order up to max_order gives the prefactor matrices Gs which are - needed for G . params = d^m f / dx^m < h. - """ +"""def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): Gs = [] for m in range(max_order): @@ -27,4 +20,17 @@ def df_dx(xi, norm_x, norm_y, p, prev_df_dx=prev_df_dx): # Jacobian w.r.t params Gm = jax.vmap(lambda xi: jax.jacobian(df_dx, argnums=3)(xi, norm_x, norm_y, params))(x) Gs.append(Gm) + return Gs""" + +def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): + Gs = [] + df_dx = f # start from f + + for m in range(max_order): + # Jacobian of current derivative w.r.t parameters + Gm = jax.vmap(lambda xi: jax.jacobian(df_dx, argnums=3)(xi, norm_x, norm_y, params))(x) + Gs.append(Gm) + + # Prepare next derivative wrt x + df_dx = jax.grad(df_dx, argnums=0) return Gs \ No newline at end of file diff --git a/maxsmooth/models.py b/maxsmooth/models.py index 2fef48a..a4608bc 100755 --- a/maxsmooth/models.py +++ b/maxsmooth/models.py @@ -9,9 +9,9 @@ def normalised_polynomial(x, norm_x, norm_y, params): return y_sum @jax.jit -def normalised_polynomial_basis(x, norm_x, order): - i = jnp.arange(order) - powers = (x / norm_x) ** i +def normalised_polynomial_basis(x, norm_x, norm_y, params): + i = jnp.arange(params.shape[0]) + powers = norm_y * (x / norm_x) ** i return powers @jax.jit @@ -22,8 +22,8 @@ def polynomial(x, norm_x, norm_y, params): return y_sum @jax.jit -def polynomial_basis(x, order): - i = jnp.arange(order) +def polynomial_basis(x, norm_x, norm_y, params): + i = jnp.arange(params.shape[0]) powers = x ** i return powers @@ -35,8 +35,8 @@ def loglog_polynomial(x, norm_x, norm_y, params): return y_sum @jax.jit -def loglog_polynomial_basis(x, order): - i = jnp.arange(order) +def loglog_polynomial_basis(x, norm_x, norm_y, params): + i = jnp.arange(params.shape[0]) powers = jnp.log10(x) ** i return powers @@ -48,9 +48,9 @@ def exponential(x, norm_x, norm_y, params): return y_sum @jax.jit -def exponential_basis(x, norm_x, order): - i = jnp.arange(order) - powers = jnp.exp(-i * x / norm_x) +def exponential_basis(x, norm_x, norm_y, params): + i = jnp.arange(params.shape[0]) + powers = norm_y * jnp.exp(-i * x / norm_x) return powers @jax.jit @@ -61,8 +61,8 @@ def log_polynomial(x, norm_x, norm_y, params): return y_sum @jax.jit -def log_polynomial_basis(x, norm_x, order): - i = jnp.arange(order) +def log_polynomial_basis(x, norm_x, norm_y, params): + i = jnp.arange(params.shape[0]) powers = jnp.log10(x / norm_x) ** i return powers @@ -74,7 +74,7 @@ def difference_polynomial(x, norm_x, norm_y, params): return y_sum @jax.jit -def difference_polynomial_basis(x, norm_x, order): - i = jnp.arange(order) +def difference_polynomial_basis(x, norm_x, norm_y, params): + i = jnp.arange(params.shape[0]) powers = (x - norm_x) ** i return powers \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index de57cb1..3c88514 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,7 @@ requires-python = ">=3.13" dependencies = [ "cvxopt>=1.3.2", "jax>=0.8.0", + "jaxopt>=0.8.5", "matplotlib>=3.10.7", "numpy>=2.3.4", "progressbar>=2.5", diff --git a/qptesting.py b/qptesting.py new file mode 100644 index 0000000..6776072 --- /dev/null +++ b/qptesting.py @@ -0,0 +1,66 @@ +from jaxopt import OSQP +from jax import numpy as jnp +from maxsmooth.models import normalised_polynomial_basis, normalised_polynomial +from maxsmooth.derivatives import derivative_prefactors, make_derivative_functions +import matplotlib.pyplot as plt +import jax +from itertools import product + +key = jax.random.PRNGKey(0) +x = jnp.linspace(2, 10, 100) +y = 5e3*x**(-2.5) + 5*jax.random.normal(key, x.shape) +N = 8 +pivot_point = 25 + +init_params = jnp.ones(N) + +basis = jax.vmap(normalised_polynomial_basis, in_axes=(0, None, None, None)) \ + (x, x[pivot_point], y[pivot_point], init_params) +Q = jnp.dot(basis.T, basis) +c = -jnp.dot(basis.T, y) +G = derivative_prefactors(normalised_polynomial, x, x[pivot_point], y[pivot_point], init_params, N) +G = G[2:] +print("Q shape:", Q.shape) +print("c shape:", c.shape) +print("G[0] shape:", G[0].shape, len(G)) + +# All possible sign combinations for the blocks of G +all_signs = list(product((-1.0, 1.0), repeat=len(G))) +print(f"Total sign combinations: {len(all_signs)}") + +all_signs = jnp.array(all_signs) + + +qp = OSQP() + +@jax.jit +def dcf(signs, c, Q): + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) # shape = (sum_rows_of_G[m], N) + h = jnp.zeros(Gmat.shape[0])*1e-6 + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h))#.params + return sol + +vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) +# Solve all QPs +sol = vmapped_dcf(all_signs, c, Q) + +exit() +sol = sol.params +print(sol) + +plt.plot(x, y, 'o', label='data') +fit = jax.vmap(normalised_polynomial, in_axes=(0, None, None, None)) \ + (x, x[pivot_point], y[pivot_point], sol.primal) +plt.plot(x, fit, '-', label='fit') +plt.legend() +plt.show() + +# Check that derivatives satisfy constraints +deriv_funcs = make_derivative_functions(normalised_polynomial, N) +derivs = [jax.vmap(df, in_axes=(0, None, None, None))(x, x[pivot_point], y[pivot_point], sol.primal) + for df in deriv_funcs] + +[plt.plot(x, derivs[m], label=f"{m}-th derivative") for m in range(len(derivs))] +plt.axhline(0, color='k', ls='--') +plt.legend() +plt.show() \ No newline at end of file diff --git a/uv.lock b/uv.lock index bec8c69..9018e5d 100644 --- a/uv.lock +++ b/uv.lock @@ -158,6 +158,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6c/82/774ff02e014ee12925388f7a77fe9beda6a8d08537666ce6259fc810b9f6/jaxlib-0.8.0-cp314-cp314t-manylinux_2_27_x86_64.whl", hash = "sha256:61cb2fde154e5a399db2880d560e3443cfa97bda9f074b545c886232ac8fe024", size = 79805953, upload-time = "2025-10-15T23:11:34.323Z" }, ] +[[package]] +name = "jaxopt" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jax" }, + { name = "jaxlib" }, + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/da/ff7d7fbd13b8ed5e8458e80308d075fc649062b9f8676d3fc56f2dc99a82/jaxopt-0.8.5.tar.gz", hash = "sha256:2790bd68ef132b216c083a8bc7a2704eceb35a92c0fc0a1e652e79dfb1e9e9ab", size = 121709, upload-time = "2025-04-14T17:59:01.618Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/d8/55e0901103c93d57bab3b932294c216f0cbd49054187ce29f8f13808d530/jaxopt-0.8.5-py3-none-any.whl", hash = "sha256:ff221d1a86908ec759eb1e219ee1d12bf208a70707e961bf7401076fe7cf4d5e", size = 172434, upload-time = "2025-04-14T17:59:00.342Z" }, +] + [[package]] name = "kiwisolver" version = "1.4.9" @@ -271,6 +286,7 @@ source = { virtual = "." } dependencies = [ { name = "cvxopt" }, { name = "jax" }, + { name = "jaxopt" }, { name = "matplotlib" }, { name = "numpy" }, { name = "progressbar" }, @@ -281,6 +297,7 @@ dependencies = [ requires-dist = [ { name = "cvxopt", specifier = ">=1.3.2" }, { name = "jax", specifier = ">=0.8.0" }, + { name = "jaxopt", specifier = ">=0.8.5" }, { name = "matplotlib", specifier = ">=3.10.7" }, { name = "numpy", specifier = ">=2.3.4" }, { name = "progressbar", specifier = ">=2.5" }, From e8c331963007784fb33c254ceaeb41be8ff4eb89 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 5 Nov 2025 16:57:48 +0000 Subject: [PATCH 10/52] tinkering and trying to parse the output of OSQP --- maxsmooth/derivatives.py | 15 ---- maxsmooth/models.py | 4 +- qptesting.py | 178 +++++++++++++++++++++++++++++++-------- 3 files changed, 144 insertions(+), 53 deletions(-) diff --git a/maxsmooth/derivatives.py b/maxsmooth/derivatives.py index 1aedb7a..d0617a1 100755 --- a/maxsmooth/derivatives.py +++ b/maxsmooth/derivatives.py @@ -7,21 +7,6 @@ def make_derivative_functions(f, max_order): derivs.append(jax.grad(derivs[-1], argnums=0)) return derivs -"""def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): - - Gs = [] - for m in range(max_order): - df_dx = f - # take m-th derivative w.r.t x - for _ in range(m): - prev_df_dx = df_dx - def df_dx(xi, norm_x, norm_y, p, prev_df_dx=prev_df_dx): - return jax.grad(prev_df_dx, argnums=0)(xi, norm_x, norm_y, p) - # Jacobian w.r.t params - Gm = jax.vmap(lambda xi: jax.jacobian(df_dx, argnums=3)(xi, norm_x, norm_y, params))(x) - Gs.append(Gm) - return Gs""" - def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): Gs = [] df_dx = f # start from f diff --git a/maxsmooth/models.py b/maxsmooth/models.py index a4608bc..dfdcaab 100755 --- a/maxsmooth/models.py +++ b/maxsmooth/models.py @@ -69,12 +69,12 @@ def log_polynomial_basis(x, norm_x, norm_y, params): @jax.jit def difference_polynomial(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = (x - norm_x) ** i + powers = (x - norm_x + 1e-6) ** i y_sum = jnp.sum(params * powers, axis=0) return y_sum @jax.jit def difference_polynomial_basis(x, norm_x, norm_y, params): i = jnp.arange(params.shape[0]) - powers = (x - norm_x) ** i + powers = (x - norm_x + 1e-6) ** i return powers \ No newline at end of file diff --git a/qptesting.py b/qptesting.py index 6776072..ccc2bca 100644 --- a/qptesting.py +++ b/qptesting.py @@ -1,25 +1,66 @@ -from jaxopt import OSQP +from jaxopt import OSQP, CvxpyQP from jax import numpy as jnp -from maxsmooth.models import normalised_polynomial_basis, normalised_polynomial +from maxsmooth.models import (difference_polynomial_basis, difference_polynomial) from maxsmooth.derivatives import derivative_prefactors, make_derivative_functions import matplotlib.pyplot as plt import jax from itertools import product +from jax.scipy.linalg import cholesky + +funciton = difference_polynomial +basis_funciton = difference_polynomial_basis + +def is_positive_definite_cholesky(A): + """ + Checks if a symmetric matrix A is positive definite using Cholesky factorization. + """ + try: + # Attempt Cholesky factorization. JAX's cholesky can return NaNs or raise an error. + # We rely on the fact that an error will be raised for non-positive definite matrices + # if check_finite=True (default in jax.scipy.linalg.cholesky). + L = cholesky(A, lower=True, check_finite=True) + # If it succeeds, the matrix is positive definite. + return True + except ValueError: + # If a ValueError (specifically LinAlgError in numpy, which maps to ValueError in jax) + # is raised, the matrix is not positive definite. + return False + except Exception as e: + # Catch other potential errors, if necessary. + print(f"An unexpected error occurred: {e}") + return False key = jax.random.PRNGKey(0) -x = jnp.linspace(2, 10, 100) -y = 5e3*x**(-2.5) + 5*jax.random.normal(key, x.shape) -N = 8 -pivot_point = 25 +x = jnp.linspace(50, 150, 100) +y = 5e3*x**(-2.5) + 0.5*jax.random.normal(key, x.shape) +#y = x**2 +N = 5 +pivot_point = len(x)//2 init_params = jnp.ones(N) -basis = jax.vmap(normalised_polynomial_basis, in_axes=(0, None, None, None)) \ +basis = jax.vmap(basis_funciton, in_axes=(0, None, None, None)) \ (x, x[pivot_point], y[pivot_point], init_params) Q = jnp.dot(basis.T, basis) +#regularization = 1e-6 * jnp.eye(N) # Small regularization term +#Q = Q + regularization + +check = is_positive_definite_cholesky(Q) +print("Is Q positive definite?", check) + c = -jnp.dot(basis.T, y) -G = derivative_prefactors(normalised_polynomial, x, x[pivot_point], y[pivot_point], init_params, N) +G = derivative_prefactors(funciton, x, x[pivot_point], y[pivot_point], init_params, N) G = G[2:] +G_scaled = [] +for i, g in enumerate(G): + # square root of sum of squares of each row + g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) + g_norm = jnp.where(g_norm < 1e-10, 1.0, g_norm) # Avoid division by zero + G_scaled.append(g / g_norm) +G = G_scaled + +print(G) + print("Q shape:", Q.shape) print("c shape:", c.shape) print("G[0] shape:", G[0].shape, len(G)) @@ -30,37 +71,102 @@ all_signs = jnp.array(all_signs) +solver = 'OSQP' + +#init_params = jnp.linalg.solve(Q, -c) + +if solver == 'OSQP': + qp = OSQP(maxiter=50000, tol=1e-3) + @jax.jit + def dcf(signs, c, Q): + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) # shape = (sum_rows_of_G[m], N) + #Gmat_norm = jnp.mean(Gmat) + #Gmat = Gmat/Gmat_norm # Centering to improve numerical stability + h = jnp.zeros(Gmat.shape[0]) + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h))#.params + return sol + + vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) + # Solve all QPs + sol = vmapped_dcf(all_signs, c, Q) -qp = OSQP() +if solver == 'CvxpyQP': + qp = CvxpyQP() -@jax.jit -def dcf(signs, c, Q): - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) # shape = (sum_rows_of_G[m], N) - h = jnp.zeros(Gmat.shape[0])*1e-6 - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h))#.params - return sol -vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) -# Solve all QPs -sol = vmapped_dcf(all_signs, c, Q) + def dcf_cvxpyqp(signs, c, Q): + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + h = jnp.zeros(Gmat.shape[0]) + + # Convert to numpy for cvxpy + Q_np = jnp.array(Q) + c_np = jnp.array(c) + Gmat_np = jnp.array(Gmat) + h_np = jnp.array(h) + + sol = qp.run(init_params=init_params, params_obj=(Q_np, c_np), params_ineq=(Gmat_np, h_np)) + return sol + + # Use a regular loop instead of vmap + solutions = [] + print(f"Solving {len(all_signs)} QPs...") + for i, signs in enumerate(all_signs): + if i % 4 == 0: # Progress indicator + print(f" Progress: {i}/{len(all_signs)}") + sol = dcf_cvxpyqp(signs, c, Q) + solutions.append(sol) + print(solutions) + +"""print("\n=== Detailed Solver Diagnostics ===") +print("Unique status values:", jnp.unique(sol.state.status)) +for status_val in jnp.unique(sol.state.status): + count = jnp.sum(sol.state.status == status_val) + indices = jnp.where(sol.state.status == status_val)[0] + print(f"\nStatus {status_val}: {count} cases") + print(f" Iteration range: {sol.state.iter_num[indices].min()}-{sol.state.iter_num[indices].max()}") + if hasattr(sol.state, 'primal_residual'): + print(f" Primal residual range: {sol.state.primal_residual[indices].min():.2e}-{sol.state.primal_residual[indices].max():.2e}") + if hasattr(sol.state, 'dual_residual'): + print(f" Dual residual range: {sol.state.dual_residual[indices].min():.2e}-{sol.state.dual_residual[indices].max():.2e}") + +# Check solution quality +print("\n=== Solution Quality ===") +for i in range(min(3, len(sol.params.primal))): + params = sol.params.primal[i] + obj_val = 0.5 * params @ Q @ params + c @ params + print(f"Solution {i}: status={sol.state.status[i]}, obj={obj_val:.3e}, |params|={jnp.linalg.norm(params):.3e}") + +""" +print(sol.state) -exit() sol = sol.params -print(sol) - -plt.plot(x, y, 'o', label='data') -fit = jax.vmap(normalised_polynomial, in_axes=(0, None, None, None)) \ - (x, x[pivot_point], y[pivot_point], sol.primal) -plt.plot(x, fit, '-', label='fit') -plt.legend() -plt.show() - -# Check that derivatives satisfy constraints -deriv_funcs = make_derivative_functions(normalised_polynomial, N) -derivs = [jax.vmap(df, in_axes=(0, None, None, None))(x, x[pivot_point], y[pivot_point], sol.primal) - for df in deriv_funcs] - -[plt.plot(x, derivs[m], label=f"{m}-th derivative") for m in range(len(derivs))] -plt.axhline(0, color='k', ls='--') -plt.legend() + +objective_values = [] +for params in sol.primal: + + #plt.plot(x, y, 'o', label='data') + fit = jax.vmap(funciton, in_axes=(0, None, None, None)) \ + (x, x[pivot_point], y[pivot_point], params) + obj_val = jnp.sum((y - fit)**2) + objective_values.append(obj_val) + """plt.plot(x, fit, '-', label='fit obj={:.2e}'.format(obj_val)) + plt.legend() + plt.show() + + # Check that derivatives satisfy constraints + deriv_funcs = make_derivative_functions(funciton, N) + derivs = [jax.vmap(df, in_axes=(0, None, None, None))(x, x[pivot_point], y[pivot_point], params) + for df in deriv_funcs] + + derivs = derivs[2:] # From 2nd derivative onwards + + [plt.plot(x, derivs[m], label=f"{m+2}-th derivative") for m in range(len(derivs))] + plt.axhline(0, color='k', ls='--') + plt.legend() + plt.show()""" + +plt.plot(objective_values, 'o-') +plt.xlabel("Solution index") +plt.ylabel("Objective value") +plt.title("Objective values for different constraint sign combinations") plt.show() \ No newline at end of file From aaacbadf61f42dfac80a000589d682fd21035c24 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 7 Nov 2025 18:47:01 +0000 Subject: [PATCH 11/52] turns out you need float64 for this kind of thing --- maxsmooth/utils.py | 20 ++++++++ qptesting.py | 112 +++++++++++++++++---------------------------- 2 files changed, 62 insertions(+), 70 deletions(-) create mode 100644 maxsmooth/utils.py diff --git a/maxsmooth/utils.py b/maxsmooth/utils.py new file mode 100644 index 0000000..cb93544 --- /dev/null +++ b/maxsmooth/utils.py @@ -0,0 +1,20 @@ +from jax.scipy.linalg import cholesky +from jax import numpy as jnp + +def is_positive_definite_cholesky(A: jnp.ndarray) -> bool: + """ + Checks if a symmetric matrix A is positive definite using Cholesky factorization. + + parameters: + ----------- + A : jnp.ndarray + Symmetric matrix to be checked. + """ + try: + _ = cholesky(A, lower=True, check_finite=True) + return True + except ValueError: + return False + except Exception as e: + print(f"An unexpected error occurred: {e}") + return False \ No newline at end of file diff --git a/qptesting.py b/qptesting.py index ccc2bca..6d1094c 100644 --- a/qptesting.py +++ b/qptesting.py @@ -1,45 +1,26 @@ from jaxopt import OSQP, CvxpyQP from jax import numpy as jnp -from maxsmooth.models import (difference_polynomial_basis, difference_polynomial) +from maxsmooth.models import (normalised_polynomial, normalised_polynomial_basis) from maxsmooth.derivatives import derivative_prefactors, make_derivative_functions import matplotlib.pyplot as plt import jax from itertools import product -from jax.scipy.linalg import cholesky - -funciton = difference_polynomial -basis_funciton = difference_polynomial_basis - -def is_positive_definite_cholesky(A): - """ - Checks if a symmetric matrix A is positive definite using Cholesky factorization. - """ - try: - # Attempt Cholesky factorization. JAX's cholesky can return NaNs or raise an error. - # We rely on the fact that an error will be raised for non-positive definite matrices - # if check_finite=True (default in jax.scipy.linalg.cholesky). - L = cholesky(A, lower=True, check_finite=True) - # If it succeeds, the matrix is positive definite. - return True - except ValueError: - # If a ValueError (specifically LinAlgError in numpy, which maps to ValueError in jax) - # is raised, the matrix is not positive definite. - return False - except Exception as e: - # Catch other potential errors, if necessary. - print(f"An unexpected error occurred: {e}") - return False +from maxsmooth.utils import is_positive_definite_cholesky + +jax.config.update('jax_enable_x64', True) + +function = normalised_polynomial +basis_function = normalised_polynomial_basis key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) -y = 5e3*x**(-2.5) + 0.5*jax.random.normal(key, x.shape) -#y = x**2 -N = 5 +y = 5e6*x**(-2.5) + 0.01*jax.random.normal(key, x.shape) +N = 8 pivot_point = len(x)//2 init_params = jnp.ones(N) -basis = jax.vmap(basis_funciton, in_axes=(0, None, None, None)) \ +basis = jax.vmap(basis_function, in_axes=(0, None, None, None)) \ (x, x[pivot_point], y[pivot_point], init_params) Q = jnp.dot(basis.T, basis) #regularization = 1e-6 * jnp.eye(N) # Small regularization term @@ -49,17 +30,16 @@ def is_positive_definite_cholesky(A): print("Is Q positive definite?", check) c = -jnp.dot(basis.T, y) -G = derivative_prefactors(funciton, x, x[pivot_point], y[pivot_point], init_params, N) +G = derivative_prefactors(function, x, x[pivot_point], y[pivot_point], init_params, N) G = G[2:] -G_scaled = [] +"""G_scaled = [] for i, g in enumerate(G): # square root of sum of squares of each row g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) g_norm = jnp.where(g_norm < 1e-10, 1.0, g_norm) # Avoid division by zero G_scaled.append(g / g_norm) -G = G_scaled +G = G_scaled""" -print(G) print("Q shape:", Q.shape) print("c shape:", c.shape) @@ -76,7 +56,7 @@ def is_positive_definite_cholesky(A): #init_params = jnp.linalg.solve(Q, -c) if solver == 'OSQP': - qp = OSQP(maxiter=50000, tol=1e-3) + qp = OSQP(maxiter=10000, tol=1e-3) @jax.jit def dcf(signs, c, Q): Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) # shape = (sum_rows_of_G[m], N) @@ -117,26 +97,6 @@ def dcf_cvxpyqp(signs, c, Q): solutions.append(sol) print(solutions) -"""print("\n=== Detailed Solver Diagnostics ===") -print("Unique status values:", jnp.unique(sol.state.status)) -for status_val in jnp.unique(sol.state.status): - count = jnp.sum(sol.state.status == status_val) - indices = jnp.where(sol.state.status == status_val)[0] - print(f"\nStatus {status_val}: {count} cases") - print(f" Iteration range: {sol.state.iter_num[indices].min()}-{sol.state.iter_num[indices].max()}") - if hasattr(sol.state, 'primal_residual'): - print(f" Primal residual range: {sol.state.primal_residual[indices].min():.2e}-{sol.state.primal_residual[indices].max():.2e}") - if hasattr(sol.state, 'dual_residual'): - print(f" Dual residual range: {sol.state.dual_residual[indices].min():.2e}-{sol.state.dual_residual[indices].max():.2e}") - -# Check solution quality -print("\n=== Solution Quality ===") -for i in range(min(3, len(sol.params.primal))): - params = sol.params.primal[i] - obj_val = 0.5 * params @ Q @ params + c @ params - print(f"Solution {i}: status={sol.state.status[i]}, obj={obj_val:.3e}, |params|={jnp.linalg.norm(params):.3e}") - -""" print(sol.state) sol = sol.params @@ -145,28 +105,40 @@ def dcf_cvxpyqp(signs, c, Q): for params in sol.primal: #plt.plot(x, y, 'o', label='data') - fit = jax.vmap(funciton, in_axes=(0, None, None, None)) \ + fit = jax.vmap(function, in_axes=(0, None, None, None)) \ (x, x[pivot_point], y[pivot_point], params) obj_val = jnp.sum((y - fit)**2) objective_values.append(obj_val) - """plt.plot(x, fit, '-', label='fit obj={:.2e}'.format(obj_val)) - plt.legend() - plt.show() - - # Check that derivatives satisfy constraints - deriv_funcs = make_derivative_functions(funciton, N) - derivs = [jax.vmap(df, in_axes=(0, None, None, None))(x, x[pivot_point], y[pivot_point], params) - for df in deriv_funcs] - - derivs = derivs[2:] # From 2nd derivative onwards - - [plt.plot(x, derivs[m], label=f"{m+2}-th derivative") for m in range(len(derivs))] - plt.axhline(0, color='k', ls='--') - plt.legend() - plt.show()""" + plt.plot(objective_values, 'o-') plt.xlabel("Solution index") plt.ylabel("Objective value") plt.title("Objective values for different constraint sign combinations") +plt.show() + +minimum_index = jnp.argmin(jnp.array(objective_values)) +best_params = sol.primal[minimum_index] +print(best_params) +plt.plot(x, y, 'o', label='data') +best_fit = jax.vmap(function, in_axes=(0, None, None, None)) \ + (x, x[pivot_point], y[pivot_point], best_params) +plt.plot(x, best_fit, '-', label='best fit obj={:.2e}'.format(objective_values[minimum_index])) +plt.legend() +plt.show() + +plt.plot(x, y - best_fit, 'o', label='residuals') +plt.axhline(0, color='k', ls='--') +plt.legend() +plt.show() + +deriv_funcs = make_derivative_functions(function, N) +derivs = [jax.vmap(df, in_axes=(0, None, None, None))(x, x[pivot_point], y[pivot_point], best_params) + for df in deriv_funcs] + +derivs = derivs[2:] # From 2nd derivative onwards + +[plt.plot(x, derivs[m], label=f"{m+2}-th derivative") for m in range(len(derivs))] +plt.axhline(0, color='k', ls='--') +plt.legend() plt.show() \ No newline at end of file From 8415ccb82be83382ea8b624acca4d26068d1a76d Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 7 Nov 2025 18:59:56 +0000 Subject: [PATCH 12/52] working replacement for the qp solver. currently solves for all signs and returns all solutions --- maxsmooth/qp.py | 318 +++++++++++++----------------------------------- qptesting.py | 92 +------------- 2 files changed, 93 insertions(+), 317 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index e1283db..6c13647 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -1,231 +1,87 @@ -from maxsmooth.derivatives import derivative_class -from maxsmooth.Models import Models_class -from cvxopt import matrix, solvers -import numpy as np -import warnings -from scipy.special import legendre, lpmv - -warnings.simplefilter('always', UserWarning) - - -class qp_class(object): - def __init__( - self, x, y, N, signs, pivot_point, model_type, cvxopt_maxiter, - zero_crossings, initial_params, - constraints, new_basis): - self.model_type = model_type - self.pivot_point = pivot_point - self.y = y - self.x = x - self.N = N - self.signs = signs - self.cvxopt_maxiter = cvxopt_maxiter - self.zero_crossings = zero_crossings - self.initial_params = initial_params - self.basis_functions = new_basis['basis_function'] - self.derivative_pres = new_basis['der_pres'] - self.model = new_basis['model'] - self.derivatives_function = new_basis['derivatives_function'] - self.args = new_basis['args'] - self.new_basis = new_basis - self.constraints = constraints - self.parameters, self.chi_squared, self.zc_dict = self.fit() - - def fit(self): - - solvers.options['maxiters'] = self.cvxopt_maxiter - solvers.options['show_progress'] = False - - def constraint_prefactors(m): - # Derivative prefactors on parameters - if self.derivative_pres is None: - if np.any(self.model_type != ['legendre', 'exponential']): - derivatives = [] - for i in range(self.N): - if i <= m - 1: - derivatives.append([0]*len(self.x)) - for i in range(self.N-m): - if self.model_type == 'normalised_polynomial': - mth_order_derivative_term = ( - self.y[self.pivot_point] / - self.x[self.pivot_point]) \ - * np.math.factorial(m + i) \ - / np.math.factorial(i) * \ - (self.x)**i/(self.x[self.pivot_point])**(i + 1) - derivatives.append(mth_order_derivative_term) - if self.model_type == 'polynomial': - mth_order_derivative_term = np.math.factorial(m+i)\ - / np.math.factorial(i) * (self.x)**i - derivatives.append(mth_order_derivative_term) - if self.model_type == 'log_polynomial': - mth_order_derivative_term = np.math.factorial(m+i)\ - / np.math.factorial(i) * \ - np.log10(self.x/self.x[self.pivot_point])**i - derivatives.append(mth_order_derivative_term) - if self.model_type == 'loglog_polynomial': - mth_order_derivative_term = np.math.factorial(m+i)\ - / np.math.factorial(i) * np.log10(self.x)**i - derivatives.append(mth_order_derivative_term) - if self.model_type == 'difference_polynomial': - mth_order_derivative_term = np.math.factorial(m+i)\ - / np.math.factorial(i) * ( - self.x - self.x[self.pivot_point])**i - derivatives.append(mth_order_derivative_term) - - if self.derivative_pres is not None: - if self.args is None: - derivatives = self.derivative_pres( - m, self.x, self.y, self.N, self.pivot_point) - if self.args is not None: - derivatives = self.derivative_pres( - m, self.x, self.y, self.N, self.pivot_point, - *self.args) - - if self.model_type == 'legendre': - interval = np.linspace(-0.999, 0.999, len(self.x)) - alps = [] - for i in range(self.N): - alps.append(lpmv(m, i, interval)) - alps = np.array(alps) - derivatives = [] - for h in range(len(alps)): - derivatives.append( - ((alps[h, :]*(-1)**(m))/(1-interval**2)**(m/2))) - derivatives = np.array(derivatives) - if self.model_type == 'exponential': - derivatives = np.empty([self.N, len(self.x)]) - for i in range(self.N): - for h in range(len(self.x)): - derivatives[i, h] = \ - self.y[self.pivot_point] * \ - (np.exp(-i*self.x[h]/self.x[self.pivot_point])) * \ - (-i/self.x[self.pivot_point])**m - derivatives = np.array(derivatives) - - derivatives = np.array(derivatives).astype(np.double) - derivatives = matrix(derivatives) - if derivatives.size == (len(self.x), self.N): - pass - else: - derivatives = derivatives.T - return derivatives - - m = np.arange(0, self.N, 1) - derivatives = [] - signs = matrix(self.signs) - for i in range(len(m)): - if m[i] >= self.constraints: - if self.zero_crossings is not None: - if m[i] not in set(self.zero_crossings): - derivative_prefactors = constraint_prefactors(m[i]) - if derivative_prefactors != []: - derivatives.append(derivative_prefactors) - else: - derivative_prefactors = constraint_prefactors(m[i]) - if derivative_prefactors != []: - derivatives.append(derivative_prefactors) - - for i in range(len(derivatives)): - derivatives[i] *= signs[i] - - G = matrix(derivatives) - - if self.basis_functions is None: - phi = np.empty([len(self.x), self.N]) - if self.model_type != 'legendre': - for h in range(len(self.x)): - for i in range(self.N): - if self.model_type == 'normalised_polynomial': - phi[h, i] = self.y[self.pivot_point] * ( - self.x[h] / self.x[self.pivot_point])**i - if self.model_type == 'polynomial': - phi[h, i] = (self.x[h])**i - if self.model_type == 'log_polynomial': - phi[h, i] = \ - np.log10(self.x[h]/self.x[self.pivot_point])**i - if self.model_type == 'loglog_polynomial': - phi[h, i] = np.log10(self.x[h])**i - if self.model_type == 'difference_polynomial': - phi[h, i] = (self.x[h]-self.x[self.pivot_point])**i - if self.model_type == 'exponential': - phi[h, i] = self.y[self.pivot_point] * \ - np.exp(-i*self.x[h]/self.x[self.pivot_point]) - if self.model_type == 'legendre': - interval = np.linspace(-0.999, 0.999, len(self.x)) - phi = [] - for i in range(self.N): - P = legendre(i) - phi.append(P(interval)) - phi = np.array(phi).T - phi = matrix(phi) - if self.basis_functions is not None: - if self.args is None: - phi = self.basis_functions( - self.x, self.y, self.pivot_point, self.N) - phi = matrix(phi) - if self.args is not None: - phi = self.basis_functions( - self.x, self.y, self.pivot_point, self.N, *self.args) - phi = matrix(phi) - - if self.model_type == 'loglog_polynomial': - data_matrix = matrix( - np.log10(self.y).astype(np.double), (len(self.y), 1), - 'd') - else: - data_matrix = matrix( - self.y.astype(np.double), (len(self.y), 1), - 'd') - - if self.zero_crossings is None: - h = matrix(0.0, ((self.N-self.constraints)*len(self.x), 1), 'd') - else: - h = matrix( - 0.0, ( - (self.N-self.constraints-len(self.zero_crossings)) - * len(self.x), 1), 'd') - - Q = phi.T*phi - - q = -phi.T*data_matrix - - if self.initial_params is None: - qpfit = solvers.qp(Q, q, G, h) - if self.initial_params is not None: - print(self.initial_params) - initvals = {'x': matrix( - self.initial_params, (1, self.N), 'd')} - qpfit = solvers.qp(Q, q, G, h, initvals=initvals) - - parameters = qpfit['x'] - - if 'unknown' in qpfit['status']: - if qpfit['iterations'] == self.cvxopt_maxiter: - raise ValueError( - 'ERROR: "Maximum number of iterations reached in' + - ' cvxopt routine." Increase value of' + - ' setting.cvxopt_maxiter') - else: - parameters = np.array(matrix(0, (self.N, 1), 'd')) - if self.model_type == 'loglog_polynomial': - chi_squared = np.sum((np.log10(self.y))**2) - else: - chi_squared = np.sum((self.y)**2) - zc_dict = {} - else: - y = Models_class( - parameters, self.x, self.y, self.N, self.pivot_point, - self.model_type, self.new_basis).y_sum - der = derivative_class( - self.x, self.y, parameters, self.N, self.pivot_point, - self.model_type, self.zero_crossings, - self.constraints, self.new_basis) - zc_dict = der.zc_dict - - if self.model_type == 'loglog_polynomial': - chi_squared = np.sum((np.log10(self.y)-np.log10(y))**2) - else: - chi_squared = np.sum((self.y-y)**2) - parameters = np.array(parameters) - - return parameters, chi_squared, zc_dict +from maxsmooth.derivatives import derivative_prefactors +from maxsmooth.utils import is_positive_definite_cholesky +from jaxopt import OSQP, CvxpyQP +from jax import numpy as jnp +from itertools import product +import jax + + +def qp(x, y, N, pivot_point, function, basis_function, solver='OSQP'): + + # needs some dummy parameters to make basis + basis = jax.vmap(basis_function, in_axes=(0, None, None, None)) \ + (x, x[pivot_point], y[pivot_point], jnp.ones(N)) + Q = jnp.dot(basis.T, basis) + #regularization = 1e-6 * jnp.eye(N) # Small regularization term + #Q = Q + regularization + + check = is_positive_definite_cholesky(Q) + print("Is Q positive definite?", check) + + c = -jnp.dot(basis.T, y) + G = derivative_prefactors(function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N) + G = G[2:] + G_scaled = [] + for i, g in enumerate(G): + # square root of sum of squares of each row + g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) + g_norm = jnp.where(g_norm < 1e-10, 1.0, g_norm) # Avoid division by zero + G_scaled.append(g / g_norm) + G = G_scaled + + + print("Q shape:", Q.shape) + print("c shape:", c.shape) + print("G[0] shape:", G[0].shape, len(G)) + + # All possible sign combinations for the blocks of G + all_signs = list(product((-1.0, 1.0), repeat=len(G))) + print(f"Total sign combinations: {len(all_signs)}") + + all_signs = jnp.array(all_signs) + + #init_params = jnp.linalg.solve(Q, -c) + + if solver == 'OSQP': + qp = OSQP(maxiter=10000, tol=1e-3) + @jax.jit + def dcf(signs, c, Q): + + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + h = jnp.zeros(Gmat.shape[0]) + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h))#.params + + return sol + + vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) + # Solve all QPs + sol = vmapped_dcf(all_signs, c, Q) + + if solver == 'CvxpyQP': + qp = CvxpyQP() + + + def dcf_cvxpyqp(signs, c, Q): + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + h = jnp.zeros(Gmat.shape[0]) + + # Convert to numpy for cvxpy + Q_np = jnp.array(Q) + c_np = jnp.array(c) + Gmat_np = jnp.array(Gmat) + h_np = jnp.array(h) + + sol = qp.run(init_params=jnp.ones(N), params_obj=(Q_np, c_np), params_ineq=(Gmat_np, h_np)) + return sol + + # Use a regular loop instead of vmap + solutions = [] + print(f"Solving {len(all_signs)} QPs...") + for i, signs in enumerate(all_signs): + if i % 4 == 0: # Progress indicator + print(f" Progress: {i}/{len(all_signs)}") + sol = dcf_cvxpyqp(signs, c, Q) + solutions.append(sol) + sol = solutions.copy() + + return {'solver': solver, 'state': sol.state, 'params': sol.params.primal, 'sol': sol} \ No newline at end of file diff --git a/qptesting.py b/qptesting.py index 6d1094c..c43026f 100644 --- a/qptesting.py +++ b/qptesting.py @@ -1,11 +1,10 @@ -from jaxopt import OSQP, CvxpyQP from jax import numpy as jnp from maxsmooth.models import (normalised_polynomial, normalised_polynomial_basis) -from maxsmooth.derivatives import derivative_prefactors, make_derivative_functions +from maxsmooth.derivatives import make_derivative_functions +from maxsmooth.qp import qp import matplotlib.pyplot as plt import jax -from itertools import product -from maxsmooth.utils import is_positive_definite_cholesky + jax.config.update('jax_enable_x64', True) @@ -20,89 +19,10 @@ init_params = jnp.ones(N) -basis = jax.vmap(basis_function, in_axes=(0, None, None, None)) \ - (x, x[pivot_point], y[pivot_point], init_params) -Q = jnp.dot(basis.T, basis) -#regularization = 1e-6 * jnp.eye(N) # Small regularization term -#Q = Q + regularization - -check = is_positive_definite_cholesky(Q) -print("Is Q positive definite?", check) - -c = -jnp.dot(basis.T, y) -G = derivative_prefactors(function, x, x[pivot_point], y[pivot_point], init_params, N) -G = G[2:] -"""G_scaled = [] -for i, g in enumerate(G): - # square root of sum of squares of each row - g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) - g_norm = jnp.where(g_norm < 1e-10, 1.0, g_norm) # Avoid division by zero - G_scaled.append(g / g_norm) -G = G_scaled""" - - -print("Q shape:", Q.shape) -print("c shape:", c.shape) -print("G[0] shape:", G[0].shape, len(G)) - -# All possible sign combinations for the blocks of G -all_signs = list(product((-1.0, 1.0), repeat=len(G))) -print(f"Total sign combinations: {len(all_signs)}") - -all_signs = jnp.array(all_signs) - -solver = 'OSQP' - -#init_params = jnp.linalg.solve(Q, -c) - -if solver == 'OSQP': - qp = OSQP(maxiter=10000, tol=1e-3) - @jax.jit - def dcf(signs, c, Q): - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) # shape = (sum_rows_of_G[m], N) - #Gmat_norm = jnp.mean(Gmat) - #Gmat = Gmat/Gmat_norm # Centering to improve numerical stability - h = jnp.zeros(Gmat.shape[0]) - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h))#.params - return sol - - vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) - # Solve all QPs - sol = vmapped_dcf(all_signs, c, Q) - -if solver == 'CvxpyQP': - qp = CvxpyQP() - - - def dcf_cvxpyqp(signs, c, Q): - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) - h = jnp.zeros(Gmat.shape[0]) - - # Convert to numpy for cvxpy - Q_np = jnp.array(Q) - c_np = jnp.array(c) - Gmat_np = jnp.array(Gmat) - h_np = jnp.array(h) - - sol = qp.run(init_params=init_params, params_obj=(Q_np, c_np), params_ineq=(Gmat_np, h_np)) - return sol - - # Use a regular loop instead of vmap - solutions = [] - print(f"Solving {len(all_signs)} QPs...") - for i, signs in enumerate(all_signs): - if i % 4 == 0: # Progress indicator - print(f" Progress: {i}/{len(all_signs)}") - sol = dcf_cvxpyqp(signs, c, Q) - solutions.append(sol) - print(solutions) - -print(sol.state) - -sol = sol.params +sol = qp(x, y, N, pivot_point, function, basis_function, solver='OSQP') objective_values = [] -for params in sol.primal: +for params in sol['params']: #plt.plot(x, y, 'o', label='data') fit = jax.vmap(function, in_axes=(0, None, None, None)) \ @@ -118,7 +38,7 @@ def dcf_cvxpyqp(signs, c, Q): plt.show() minimum_index = jnp.argmin(jnp.array(objective_values)) -best_params = sol.primal[minimum_index] +best_params = sol['params'][minimum_index] print(best_params) plt.plot(x, y, 'o', label='data') best_fit = jax.vmap(function, in_axes=(0, None, None, None)) \ From c5a30fa57ecbc74e67674f0f6c133721d6a5e56b Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 7 Nov 2025 19:08:55 +0000 Subject: [PATCH 13/52] i dont think these helper funcitons are needed. users can design and make their own plots --- maxsmooth/chidist_plotter.py | 272 ---------------- maxsmooth/parameter_plotter.py | 558 --------------------------------- 2 files changed, 830 deletions(-) delete mode 100644 maxsmooth/chidist_plotter.py delete mode 100644 maxsmooth/parameter_plotter.py diff --git a/maxsmooth/chidist_plotter.py b/maxsmooth/chidist_plotter.py deleted file mode 100644 index a00e50b..0000000 --- a/maxsmooth/chidist_plotter.py +++ /dev/null @@ -1,272 +0,0 @@ -""" - -This function allows the user to produce plots of the chi squared -distribution as a function of the available discrete sign spaces for the -constrained derivatives. This can be used to identify whether or not the -problem is `ill defined`, see the ``maxsmooth`` paper for a definition, -and if it can be solved using the sign sampling approach. - -It can also be used to determine whether or not the 'cap' and maximum allowed -increase on the value of chi squared during the directional exploration -are sufficient to identify the global minimum for the problem. - -The function is reliant on the output of the ``maxsmooth`` smooth() function. -The required outputs can be saved when running smooth() -using the 'data_save = True' kwarg. -""" - -import numpy as np -import os -from itertools import product -import matplotlib.pyplot as plt - - -class chi_plotter(object): - - r""" - - **Parameters:** - - N: **int** - | The number of terms in the DCF. - - **Kwargs:** - - fit_type: **Default = 'qp-sign_flipping'** - | This kwarg is the same as for the smooth() function. - Here it allows the files to be read from the base - directory. - - base_dir: **Default = 'Fitted_Output/'** - | The location of the outputted - data from ``maxsmooth``. This must be a string and end in '/' - and must contain the files 'Output_Evaluations/' and - 'Output_Signs/' which can be obtained by running smooth() with - data_save=True. - - chi: **Default = None else list or numpy array** - | A list of - chi squared evaluations. If provided then this is used - over outputted data in the base directory. It must have the - same length as the ouputted signs in the file 'Output_Signs/' - in the base directory. It must also be ordered correctly - otherwise the returned graph will not be correct. A correct - ordering is one for which each entry in the array corresponds - to the correct sign combination in 'Output_Signs/'. - Typically this will not be needed but if the chi squared - evaluation in 'Output_Evaluations/' in the base directory - is not in the desired parameter space this can be useful. - For example the built in logarithmic model calculates - chi squared in logarithmic space. To plot the distribution - in linear space we can calculate - chi squared in linear space using a function for the model - and the tested parameters which are found in - 'Output_Parameters/' in the base directory. - - **constraints: Default = 2 else an integer less than or equal** - **to N - 1** - | The minimum constrained derivative order which is set by default - to 2 for a Maximally Smooth Function. Used here to determine - the number of possible sign combinations available. - - zero_crossings: **Default = None else list of integers** - | Allows you to - specify if the conditions should be relaxed on any - of the derivatives between constraints and the highest order - derivative. e.g. a 6th order fit with just a constrained 2nd - and 3rd order derivative would have a zero_crossings = [4, 5]. - Again this is used in determining the possible sign - combinations available. - - plot_limits: **Default = False** - | Determines whether the limits on - the directional exploration are plotted on top of the - chi squared distribution. - - cap: **Default = (len(available_signs)//N) + N else an integer** - | Determines the maximum number of signs explored either side of - the minimum chi squared value found after the - decent algorithm has terminated when running smooth(). Here - it is used when plot_limits=True. - - chi_squared_limit: **Default = 2 else float or int** - | The prefactor on the maximum allowed increase in chi squared - during the directional exploration which is defaulted at 2. - If this value multiplied by the minimum chi squared - value found after the descent algorithm is exceeded then the - exploration in one direction is stopped and started in the - other. For more details on this and 'cap' see the ``maxsmooth`` - paper. Again this is used here - when plot_limits=True. - - """ - def __init__(self, N, **kwargs): - - self.N = N - if self.N % 1 != 0: - raise ValueError('N must be an integer or whole number float.') - - for keys, values in kwargs.items(): - if keys not in set([ - 'chi', 'base_dir', - 'zero_crossings', 'constraints', - 'fit_type', 'chi_squared_limit', 'cap', 'plot_limits']): - raise KeyError("Unexpected keyword argument in chi_plotter().") - - self.base_dir = kwargs.pop('base_dir', 'Fitted_Output/') - if type(self.base_dir) is not str: - raise KeyError("'base_dir' must be a string ending in '/'.") - elif self.base_dir.endswith('/') is False: - raise KeyError("'base_dir' must end in '/'.") - - if not os.path.exists(self.base_dir): - raise Exception( - "'base_dir' must exist and contain the outputted" - + " evaluations and sign combinations from a maxsmooth fit." - + " These can be obtained by running maxsmooth with" - + " 'data_save=True'.") - else: - if not os.path.exists(self.base_dir + 'Output_Evaluation/'): - raise Exception( - "No 'Output_Evaluation/' directory found in" - + " 'base_dir'.") - if not os.path.exists(self.base_dir + 'Output_Signs/'): - raise Exception( - "No 'Output_Signs/' directory found in" - + " 'base_dir'.") - - self.chi = kwargs.pop('chi', None) - - self.constraints = kwargs.pop('constraints', 2) - if type(self.constraints) is not int: - raise TypeError("'constraints' is not an integer") - if self.constraints > self.N-1: - raise ValueError( - "'constraints' exceeds the number" + - " of derivatives.") - - self.zero_crossings = kwargs.pop('zero_crossings', None) - if self.zero_crossings is not None: - for i in range(len(self.zero_crossings)): - if type(self.zero_crossings[i]) is not int: - raise TypeError( - "Entries in 'zero_crossings'" + - " are not integer.") - if self.zero_crossings[i] < self.constraints: - raise ValueError( - 'One or more specified derivatives for' + - ' zero crossings is less than the minimum' + - ' constrained' + - ' derivative.\n zero_crossings = ' - + str(self.zero_crossings) - + '\n' + ' Minimum Constrained Derivative = ' - + str(self.constraints)) - - self.fit_type = kwargs.pop('fit_type', 'qp-sign_flipping') - if self.fit_type not in set(['qp', 'qp-sign_flipping']): - raise KeyError( - "Invalid 'fit_type'. Valid entries include 'qp'\n" + - "'qp-sign_flipping'") - - self.chi_squared_limit = kwargs.pop('chi_squared_limit', None) - self.cap = kwargs.pop('cap', None) - if self.chi_squared_limit is not None: - if isinstance(self.chi_squared_limit, int) or \ - isinstance(self.chi_squared_limit, float): - pass - else: - raise TypeError( - "Limit on maximum allowed increase in chi squared" + - ", 'chi_squared_limit', is not an integer or float.") - if self.cap is not None: - if type(self.cap) is not int: - raise TypeError( - "The cap on directional exploration" + - ", 'cap', is not an integer.") - - self.plot_limits = kwargs.pop('plot_limits', False) - if type(self.plot_limits) is not bool: - raise TypeError( - "Boolean keyword argument with value " - + " 'plot_limits' is not True or False.") - - self.plot() - - def plot(self): - - def signs_array(nums): - return np.array(list(product(*((x, -x) for x in nums)))) - - if self.zero_crossings is not None: - possible_signs = signs_array([1]*( - self.N-self.constraints-len(self.zero_crossings))) - else: - possible_signs = signs_array([1]*(self.N-self.constraints)) - - plt.figure() - j = np.arange(0, len(possible_signs), 1) - if self.chi is None: - chi = np.loadtxt( - self.base_dir + 'Output_Evaluation/' - + str(self.N) + '_' + str(self.fit_type) + '.txt') - signs = np.loadtxt( - self.base_dir + 'Output_Signs/' - + str(self.N) + '_' + str(self.fit_type) + '.txt') - if len(signs) != len(possible_signs): - index = [] - for p in range(len(signs)): - for i in range(len(possible_signs)): - if np.all(signs[p] == possible_signs[i]): - index.append(i) - index, chi = zip(*sorted(zip(index, chi))) - plt.plot(index, chi, ls='-') - else: - plt.plot(j, chi, marker='.', ls='-') - else: - chi = self.chi - signs = np.loadtxt( - self.base_dir + 'Output_Signs/' - + str(self.N) + '_' + str(self.fit_type) + '.txt') - if len(signs) != len(possible_signs): - index = [] - for p in range(len(signs)): - for i in range(len(possible_signs)): - if np.all(signs[p] == possible_signs[i]): - index.append(i) - index, chi = zip(*sorted(zip(index, chi))) - plt.plot(index, chi, marker='.', ls='-') - else: - plt.plot(j, chi, marker='.', ls='-') - - if self.cap is None: - self.cap = (len(possible_signs)//self.N) + self.N - if self.chi_squared_limit is None: - self.chi_squared_limit = 2*min(chi) - - for i in range(len(chi)): - if chi[i] == min(chi): - plt.plot(i, chi[i], marker='*') - if self.plot_limits is True: - plt.vlines( - i + self.cap, min(chi), max(chi), ls='--', - label='Cap On Exp.', color='k', alpha=0.5) - plt.vlines( - i - self.cap, min(chi), max(chi), - ls='--', color='k', alpha=0.5) - if self.plot_limits is True: - min_chi = np.load( - self.base_dir + str(self.N) + - '_'+self.fit_type+'_minimum_chi_post_descent.npy') - plt.hlines( - self.chi_squared_limit*min_chi, 0, len(possible_signs), - ls='-.', label=r'Max. Increase\n' + - ' in $\chi^2$', # noqa: W605 - color='k', alpha=0.5) - plt.xlim([j[0], j[-1]]) - plt.grid() - plt.yscale('log') - plt.ylabel(r'$\chi^2$') - plt.xlabel('Sign Combination') - plt.tight_layout() - plt.savefig(self.base_dir + 'chi_distribution.pdf') - plt.close() diff --git a/maxsmooth/parameter_plotter.py b/maxsmooth/parameter_plotter.py deleted file mode 100644 index d6b023f..0000000 --- a/maxsmooth/parameter_plotter.py +++ /dev/null @@ -1,558 +0,0 @@ -""" -This function allows you to plot the parameter space around the optimum -solution found when running ``maxsmooth`` and visualise the constraints with -contour lines given by chi squared. -""" - -import warnings -import numpy as np -import itertools -import matplotlib.pyplot as plt -import progressbar -from itertools import product -from maxsmooth import Models -from maxsmooth.derivatives import derivative_class -import os - - -class param_plotter(object): - - r""" - - **Parameters:** - - best_params: **numpy.array** - | The optimum parameters found when running - a DCF fit to the data. - - optimum_signs: **numpy.array** - | The optimum signs for the DCF fit which - are used when the derivatives are equal to 0 across the band. - - x: **numpy.array** - | The x data points. - - y: **numpy.array** - | The y data points. - - N: **int** - | The number of terms in the DCF. - - **Kwargs:** - - model_type: **Default = 'difference_polynomial'** - | The functional form of - the model being plotted. If a the user has defined their own - basis they can supply this with the Kwargs below and this - will be overwritten. - - base_dir: **Default = 'Fitted_Output/'** - | The location in which the - parameter plot is saved. - - **constraints: Default = 2 else an integer less than or equal** - **to N - 1** - | The minimum constrained derivative order which is set by default - to 2 for a Maximally Smooth Function. Used here to - determine the number of possible sign combinations available. - - zero_crossings: **Default = None else list of integers** - | Allows you to - specify if the conditions should be relaxed on any - of the derivatives between constraints and the highest order - derivative. e.g. a 6th order fit with just a constrained - 2nd and 3rd order derivative would have an - zero_crossings = [4, 5]. - Again this is used in determining the possible sign - combinations available. - - samples: **Default = 50** - | The sampling rate across the parameter ranges - defined with the optimum solution and width. - - width: **Default = 0.5** - | The range of each parameter to explore. The - default value of 0.5 means that the :math:`{\chi^2}` - values for parameters ranging 50% either side of the optimum - result are tested. - - warnings: **Default = True** - | Used to highlight when a derivative is - 0 across the band and that in these instances the optimum - signs are assumed for the colourmap if :math:`{N \leq 5}`, - constraints=2 and the zero_crossings is empty. - - girdlines: **Default = False** - | Plots gridlines showing the central value - for each parameter in each panel of the plot. - - center_plot: **Default = False** - | Setting this equal to True will highlight the central region - with a white circle. - - data_plot: **Default = False** - | Setting to True will plot the data, fitted model and the - residuals, :math:`{y - y_{fit}}`, alongside the - parameter graph. - - The following Kwargs are used to plot the parameter space for a user - defined basis function and will overwrite the 'model_type' kwarg. - - **basis_function: Default = None else function with parameters** - **(x, y, pivot_point, N)** - | This is a function of basis functions - for the quadratic programming. The variable pivot_point is the - index at the middle of the datasets x and y by default but can - be adjusted. - - **model: Default = None else function with parameters** - **(x, y, pivot_point, N, params)** - | This is - a user defined function describing the model to be fitted to - the data. - - **der_pres: Default = None else function with parameters** - **(m, x, y, N, pivot_point)** - | This function describes the prefactors on the - mth order derivative used in defining the constraint. - - **derivatives: Default = None else function with parameters** - **(m, x, y, N, pivot_point, params)** - | User defined function describing the mth - order derivative used to check that conditions are being met. - - **args: Default = None else list** - | Extra arguments for `smooth` - to pass to the functions detailed above. - - """ - - def __init__(self, best_params, optimum_signs, x, y, N, **kwargs): - self.best_params = best_params - self.optimum_signs = optimum_signs - self.x = x - self.y = y - - self.N = N - if self.N % 1 != 0: - raise ValueError('N must be an integer or whole number float.') - - for keys, values in kwargs.items(): - if keys not in set([ - 'model_type', 'base_dir', - 'zero_crossings', 'constraints', - 'basis_functions', 'der_pres', 'model', - 'derivatives', 'args', 'pivot_point', 'samples', - 'width', 'warnings', 'gridlines', 'center_plot', - 'data_plot']): - raise KeyError( - "Unexpected keyword argument in param_plotter().") - - self.model_type = kwargs.pop('model_type', 'difference_polynomial') - if self.model_type not in set([ - 'normalised_polynomial', 'polynomial', - 'log_polynomial', 'loglog_polynomial', 'difference_polynomial', - 'exponential', 'legendre']): - raise KeyError( - "Invalid 'model_type'. See documentation for built" + - "in models.") - - self.basis_functions = kwargs.pop('basis_functions', None) - self.der_pres = kwargs.pop('der_pres', None) - self.model = kwargs.pop('model', None) - self.derivatives_function = kwargs.pop('derivatives', None) - self.args = kwargs.pop('args', None) - - self.new_basis = { - 'basis_function': - self.basis_functions, 'der_pres': self.der_pres, - 'derivatives_function': self.derivatives_function, - 'model': self.model, 'args': self.args} - if np.all([value is None for value in self.new_basis.values()]): - pass - else: - count = 0 - for key, value in self.new_basis.items(): - if value is None and key != 'args': - raise KeyError( - 'Attempt to change basis functions failed.' + - ' One or more functions not defined.' + - ' Please consult documentation.') - if value is None and key == 'args': - warnings.warn( - 'Warning: No additional arguments passed' + - ' to new basis functions') - count += 1 - if count == len(self.new_basis): - self.model_type = 'user_defined' - - self.pivot_point = kwargs.pop('pivot_point', len(self.x)//2) - if type(self.pivot_point) is not int: - raise TypeError('Pivot point is not an integer index.') - elif self.pivot_point >= len(self.x) or \ - self.pivot_point < -len(self.x): - raise ValueError( - 'Pivot point must be in the range -len(x) - len(x).') - - self.base_dir = kwargs.pop('base_dir', 'Fitted_Output/') - if type(self.base_dir) is not str: - raise KeyError("'base_dir' must be a string ending in '/'.") - elif self.base_dir.endswith('/') is False: - raise KeyError("'base_dir' must end in '/'.") - - if not os.path.exists(self.base_dir): - os.mkdir(self.base_dir) - - self.constraints = kwargs.pop('constraints', 2) - if type(self.constraints) is not int: - raise TypeError("'constraints' is not an integer") - if self.constraints > self.N-1: - raise ValueError( - "'constraints' exceeds the number of derivatives.") - - self.zero_crossings = kwargs.pop('zero_crossings', None) - if self.zero_crossings is not None: - for i in range(len(self.zero_crossings)): - if type(self.zero_crossings[i]) is not int: - raise TypeError( - "Entries in 'zero_crossings'" + - " are not integer.") - if self.zero_crossings[i] < self.constraints: - raise ValueError( - 'One or more specified derivatives for' + - ' inflection points is less than the minimum' + - ' constrained' + - ' derivative.\n zero_crossings = ' - + str(self.zero_crossings) - + '\n' + ' Minimum Constrained Derivative = ' - + str(self.constraints)) - - self.samples = kwargs.pop('samples', 50) - if self.samples % 1 != 0: - raise ValueError('Error: Samples must be a whole number.') - - self.width = kwargs.pop('width', 0.5) - if type(self.width) is not int: - if type(self.width) is not float: - raise ValueError('Width must be an integer or a float.') - - self.warnings = kwargs.pop('warnings', True) - self.gridlines = kwargs.pop('gridlines', False) - self.data_plot = kwargs.pop('data_plot', False) - self.center_plot = kwargs.pop('center_plot', False) - boolean_kwargs = [ - self.warnings, self.gridlines, - self.center_plot, self.data_plot] - for i in range(len(boolean_kwargs)): - if type(boolean_kwargs[i]) is not bool: - raise TypeError( - "Boolean keyword argument with value " - + str(boolean_kwargs[i]) + - " is not True or False.") - - self.plot() - - def plot(self): - - def chi_squared(parameters): - y_sum = Models.Models_class( - parameters, self.x, self.y, - self.N, self.pivot_point, self.model_type, - self.new_basis).y_sum - if self.model_type == 'loglog_polynomial': - chi = np.sum((np.log10(self.y) - np.log10(y_sum))**2) - else: - chi = np.sum((self.y - y_sum)**2) - return chi - - def plot_formatting(xpos, ypos): - ypos -= 1 - if xpos == 0: - axes[ypos, xpos].set_ylabel(r'$a_{%2d}$' % i1, fontsize=12) - if xpos != 0: - axes[ypos, xpos].set_yticklabels([]) - if ypos == self.N-2: - axes[ypos, xpos].set_xlabel(r'$a_{%2d}$' % i2, fontsize=12) - if ypos != self.N-2: - axes[ypos, xpos].set_xticklabels([]) - for label in axes[ypos, xpos].get_xticklabels(): - label.set_rotation(90) - - def signs_array(nums): - return np.array(list(product(*((x, -x) for x in nums)))) - - if self.zero_crossings is not None: - available_signs = signs_array([1]*( - self.N-self.constraints-len(self.zero_crossings))) - else: - available_signs = signs_array([1]*(self.N-self.constraints)) - - indices = np.array([np.arange(0, self.N, 1), np.arange(0, self.N, 1)]) - combinations = list(itertools.product(*indices)) - - combis = [] - for i in range(len(combinations)): - if combinations[i][0] != combinations[i][1]: - combis.append(combinations[i]) - for j in range(len(combis)): - if combis[-1] == tuple(sorted(combis[j])): - combis.remove(combis[-1]) - - bar = progressbar.ProgressBar( - maxval=len(combis), - widgets=[ - progressbar.Bar('#', '[', ']'), ' ', - progressbar.Percentage()]) - bar.start() - mapped_colours = [] - cp_array = [] - sign_combinations = [] - warnings_count = 0 - - if self.data_plot is True: - fig, axes = plt.subplots( - figsize=(15, 10), nrows=self.N-1, - ncols=self.N-1) - else: - fig, axes = plt.subplots( - figsize=(10, 10), nrows=self.N-1, - ncols=self.N-1) - - for n in range(self.N-1): - for m in range(self.N-1): - if n < m: - axes[n, m].axis('off') - for f in range(len(combis)): - bar.update(f+1) - i1 = combis[f][0] - i2 = combis[f][1] - p = [] - for i in range(self.N): - if i == i1 or i == i2: - p.append( - np.linspace( - self.best_params[i] * (1 - self.width), - self.best_params[i] * (1 + self.width), - self.samples)) - p = np.array(p).T[0] - best = [ - list(self.best_params[i2])[0], list(self.best_params[i1])[0]] - p = list(p) - p.insert(len(p)//2, best) - p = np.array(p) - - comb, id = [], [] - for i in range(self.N): - if i != i1 and i != i2: - id.append(i) - comb.append(self.best_params[i]) - comb, id = np.array(comb).T[0], np.array(id) - - X, Y = np.meshgrid(p[:, 0], p[:, 1]) - - chi = np.empty(X.shape) - pf = np.empty(X.shape) - if self.N <= 5: - s = np.empty(X.shape) - for i in range(s.shape[0]): - for j in range(s.shape[1]): - s[i, j] = len(available_signs)+10 - - for j in range(X.shape[0]): - for a in range(X.shape[1]): - parameters = np.empty(self.N) - parameters[i1] = Y[j, a].copy() - parameters[i2] = X[j, a].copy() - for h in range(len(id)): - parameters[id[h]] = comb[h] - parameters = np.array(parameters) - chi[j, a] = chi_squared(parameters) - - if self.model_type == 'legendre': - parameters = np.array([parameters]).T - - der = derivative_class( - self.x, self.y, - parameters, self.N, - self.pivot_point, self.model_type, - self.zero_crossings, self.constraints, - self.new_basis, call_type='plotter') - - derivatives, pass_fail = der.derivatives, der.pass_fail - - if np.any(pass_fail == 0): - pf[j, a] = 0 - else: - pf[j, a] = 1 - - if self.N <= 5: - signs = [] - for i in range(derivatives.shape[0]): - if (np.all(derivatives[i, :] >= -1e-6)) and \ - (np.all(derivatives[i, :] <= 1e-6)): - signs.append(self.optimum_signs) - if self.warnings is True and \ - warnings_count == 0: - warnings.warn( - 'Warning: One or more derivatives' - + ' equals 0 across the band. Optimum' - + ' derivative signs from maxsmooth' - + ' assumed for these derivatives' - + ' which may cause inconsistencies' - + ' in the parameter plot.') - warnings_count += 1 - elif (np.all(derivatives[i, :] >= -1e-6)): - signs.append(-1) - elif (np.all(derivatives[i, :] <= 1e-6)): - signs.append(+1) - - for i in range(len(available_signs)): - if np.all(signs == available_signs[i]) \ - and pf[j, a] != 0: - s[j, a] = i - - chi_masked = np.ma.masked_where(pf == 0, chi) - chi_fail_masked = np.ma.masked_where(pf == 1, chi) - - if self.N <= 5: - chi_array = [] - for i in range(len(available_signs)): - array = chi_masked.copy() - chi_array.append(np.ma.masked_where(s != i, array)) - - plot_formatting(i2, i1) - - with warnings.catch_warnings(): - warnings.simplefilter('ignore') - if self.N > 5 or self.constraints != 2: - cp = axes[i1 - 1, i2].contourf( - X, Y, chi_masked, - np.linspace(chi.min(), chi.max(), 10), - cmap='autumn') - if f == len(combis) - 1: - if self.data_plot is True: - cbax = fig.add_axes([0.7*11/15, 0.88, 0.2, 0.02]) - else: - cbax = fig.add_axes([0.61, 0.88, 0.25, 0.02]) - clb = plt.colorbar( - cp, cax=cbax, - orientation='horizontal') - clb.ax.set_ylabel( - r'Valid Region', rotation=0, - fontsize=10) - clb.ax.yaxis.set_label_coords(-0.2, 0.1) - clb.ax.tick_params(rotation=90) - else: - cps, mapped_colours_combi = [], [] - mapped_sign_combinations = [] - cmaps = [ - 'autumn', 'winter', 'summer', 'spring', - 'Greens', 'cool', 'pink', 'ocean'] - for i in range(len(available_signs)): - if np.all(chi_array[i].mask): - pass - else: - cp = axes[i1 - 1, i2].contourf( - X, Y, chi_array[i], - np.linspace(chi.min(), chi.max(), 10), - cmap=cmaps[i]) - cps.append(cp) - mapped_colours_combi.append(cmaps[i]) - mapped_sign_combinations.append(available_signs[i]) - cp_array.append(cps) - mapped_colours.append(mapped_colours_combi) - sign_combinations.append(mapped_sign_combinations) - cp_fail = axes[i1 - 1, i2].contourf( - X, Y, chi_fail_masked, - np.linspace(chi.min(), chi.max(), 10), - cmap='gray') - if f == len(combis) - 1: - if self.data_plot is True: - cbax = fig.add_axes([0.7*11/15, 0.9, 0.2, 0.02]) - else: - cbax = fig.add_axes([0.61, 0.9, 0.25, 0.02]) - clb = plt.colorbar( - cp_fail, cax=cbax, - orientation='horizontal') - clb.ax.set_title(r'$\chi^2$') - clb.ax.set_ylabel( - r'Invalid Region', rotation=0, - fontsize=10) - clb.ax.yaxis.set_label_coords(-0.2, 0.1) - clb.ax.tick_params( - labelcolor="none", bottom=False, left=False) - - if self.center_plot is True: - axes[i1 - 1, i2].plot( - self.best_params[i2], self.best_params[i1], - color='w', marker='o', - fillstyle='none', markersize=10) - if self.gridlines is True: - axes[i1 - 1, i2].vlines( - self.best_params[i2], p[:, 1].min(), - p[:, 1].max(), color='w', ls='--') - axes[i1 - 1, i2].hlines( - self.best_params[i1], p[:, 0].min(), - p[:, 0].max(), color='w', ls='--') - bar.finish() - - cbaxes = [] - height = 0.88 - - if self.N <= 5: - mapped_colours = list( - itertools.chain.from_iterable(mapped_colours)) - cp_array = list(itertools.chain.from_iterable(cp_array)) - sign_combinations = list( - itertools.chain.from_iterable(sign_combinations)) - unique_mapped_colours, indices = np.unique( - np.array(mapped_colours), return_index=True) - for i in range(len(unique_mapped_colours)): - if i > 0: - height -= 0.02 - if self.data_plot is True: - cbaxes.append( - fig.add_axes([0.7*11/15, height, 0.2, 0.02])) - else: - cbaxes.append( - fig.add_axes([0.61, height, 0.25, 0.02])) - count = 0 - for i in range(len(cp_array)): - if i in set(indices): - clb = plt.colorbar( - cp_array[i], cax=cbaxes[count], - orientation='horizontal') - clb.ax.set_ylabel( - r'$\mathbf{s}$ = ' + str(sign_combinations[i]), - rotation=0, fontsize=10) - clb.ax.yaxis.set_label_coords(-0.25, 0.1) - if i != indices.max(): - clb.ax.tick_params( - labelcolor="none", bottom=False, left=False) - else: - clb.ax.tick_params(rotation=90) - count += 1 - - plt.subplots_adjust(wspace=0.1, hspace=0.1) - - if self.data_plot is True: - fig.subplots_adjust(right=4.5/6.3) - fig.add_axes([11.5/15, 0.55, 3/15, 0.35]) - plt.plot(self.x, self.y, label='Data') - plt.ylabel(r'$y$') - y_sum = Models.Models_class( - self.best_params, self.x, self.y, - self.N, self.pivot_point, self.model_type, - self.new_basis).y_sum - plt.plot(self.x, y_sum, label='Fit') - plt.legend(loc=0) - fig.add_axes([11.5/15, 0.15, 3/15, 0.35]) - plt.plot( - self.x, self.y - y_sum, label='RMS = %2.1f' - % (np.sqrt(np.sum((self.y - y_sum)**2)/len(self.y)))) - plt.legend(loc=0) - plt.ylabel(r'$\delta y$') - plt.xlabel(r'$x$') - - plt.savefig(self.base_dir + 'Parameter_plot.pdf') - plt.close() From 51a3abc2e92d62f3d1e5f3fad0dfa046c936a1dd Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 7 Nov 2025 19:11:24 +0000 Subject: [PATCH 14/52] removing save functions. users can decide what they want to keep --- maxsmooth/Data_save.py | 94 ------------------------------------------ 1 file changed, 94 deletions(-) delete mode 100755 maxsmooth/Data_save.py diff --git a/maxsmooth/Data_save.py b/maxsmooth/Data_save.py deleted file mode 100755 index f3ca144..0000000 --- a/maxsmooth/Data_save.py +++ /dev/null @@ -1,94 +0,0 @@ -import numpy as np -import os - - -class save(object): - def __init__(self, base_dir, params, chi_squared, signs, N, fit_type): - self.base_dir = base_dir - self.params = params - self.chi_squared = chi_squared - self.signs = [signs] - self.N = N - self.fit_type = fit_type - - if not os.path.exists(self.base_dir+'Output_Parameters/'): - os.mkdir(self.base_dir+'Output_Parameters/') - - with open( - self.base_dir+'Output_Parameters/'+str(self.N) + - '_'+self.fit_type+'.txt', 'a') as f: - np.savetxt(f, np.array(self.params).T) - f.close() - - if not os.path.exists(self.base_dir+'Output_Signs/'): - os.mkdir(self.base_dir+'Output_Signs/') - - with open( - self.base_dir+'Output_Signs/'+str(self.N) + - '_'+self.fit_type+'.txt', 'a') as f: - np.savetxt(f, self.signs) - f.close() - - if not os.path.exists(self.base_dir+'Output_Evaluation/'): - os.mkdir(self.base_dir+'Output_Evaluation/') - - with open( - self.base_dir+'Output_Evaluation/'+str(self.N) + - '_'+self.fit_type+'.txt', 'a') as f: - np.savetxt(f, np.array([self.chi_squared])) - f.close() - - -class save_optimum(object): - def __init__( - self, base_dir, time, N, Optimum_signs, Optimum_chi_squared, - Optimum_params, fit_type, model_type, zero_crossings, - Optimum_zc_dict, constraints): - self.base_dir = base_dir - self.time = time - self.N = N - self.Optimum_signs = Optimum_signs - self.Optimum_chi_squared = Optimum_chi_squared - self.Optimum_params = Optimum_params - self.fit_type = fit_type - self.model_type = model_type - self.zero_crossings = zero_crossings - self.Optimum_zc_dict = Optimum_zc_dict - self.constraints = constraints - - f = open( - self.base_dir + 'Optimal_Results_'+self.fit_type + - '_'+str(N)+'.txt', 'w') - f.write('Time:\n') - np.savetxt(f, np.array([self.time])) - f.write('Polynomial Order:\n') - np.savetxt(f, np.array([self.N])) - f.write('Number of Derivatives:\n') - if self.zero_crossings is None: - np.savetxt(f, np.array([self.N-self.constraints])) - else: - np.savetxt(f, np.array( - [self.N-self.constraints-len(self.zero_crossings)])) - f.write('Signs:\n') - np.savetxt(f, self.Optimum_signs) - f.write('Objective Function Value:\n') - np.savetxt(f, np.array([self.Optimum_chi_squared])) - f.write('Parameters:\n') - np.savetxt(f, self.Optimum_params) - f.write('Method:\n') - f.write(self.fit_type+'\n') - f.write('Model:\n') - f.write(self.model_type+'\n') - f.write('Constraints'+'\n') - np.savetxt(f, np.array([self.constraints])) - if self.zero_crossings is None: - f.write('Zero crossings Used? (0 signifies Yes):\n') - f.write(str(self.Optimum_zc_dict)) - if self.zero_crossings is not None: - f.write('Zero Crossing Derivatives:\n') - np.savetxt(f, self.zero_crossings) - f.write( - 'Zero crossings Used? (0 signifies' + - ' Yes\n in derivative order "i"):\n') - f.write(str(self.Optimum_zc_dict)) - f.close() From dfbe169082f65a7137c443d6cf12f0c9db2deacb Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 7 Nov 2025 19:16:09 +0000 Subject: [PATCH 15/52] updating uv stuff --- .python-version | 1 + pyproject.toml | 1 + uv.lock | 223 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 .python-version diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/pyproject.toml b/pyproject.toml index 3c88514..e927bf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ readme = "README.md" requires-python = ">=3.13" dependencies = [ "cvxopt>=1.3.2", + "cvxpy>=1.7.3", "jax>=0.8.0", "jaxopt>=0.8.5", "matplotlib>=3.10.7", diff --git a/uv.lock b/uv.lock index 9018e5d..5216005 100644 --- a/uv.lock +++ b/uv.lock @@ -2,6 +2,69 @@ version = 1 revision = 2 requires-python = ">=3.13" +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "clarabel" +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/e2/47f692161779dbd98876015de934943effb667a014e6f79a6d746b3e4c2a/clarabel-0.11.1.tar.gz", hash = "sha256:e7c41c47f0e59aeab99aefff9e58af4a8753ee5269bbeecbd5526fc6f41b9598", size = 253949, upload-time = "2025-06-11T16:49:05.864Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/f7/f82698b6d00a40a80c67e9a32b2628886aadfaf7f7b32daa12a463e44571/clarabel-0.11.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c39160e4222040f051f2a0598691c4f9126b4d17f5b9e7678f76c71d611e12d8", size = 1039511, upload-time = "2025-06-11T16:48:58.525Z" }, + { url = "https://files.pythonhosted.org/packages/b0/8f/13650cfe25762b51175c677330e6471d5d2c5851a6fbd6df77f0681bb34e/clarabel-0.11.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8963687ee250d27310d139eea5a6816f9c3ae31f33691b56579ca4f0f0b64b63", size = 935135, upload-time = "2025-06-11T16:48:59.901Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9e/7af10d2b540b39f1a05d1ebba604fce933cc9bc0e65e88ec3b7a84976425/clarabel-0.11.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4837b9d0db01e98239f04b1e3526a6cf568529d3c19a8b3f591befdc467f9bb", size = 1079226, upload-time = "2025-06-11T16:49:00.987Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a9/c76edf781ca3283186ff4b54a9a4fb51367fd04313a68e2b09f062407439/clarabel-0.11.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8c41aaa6f3f8c0f3bd9d86c3e568dcaee079562c075bd2ec9fb3a80287380ef", size = 1164345, upload-time = "2025-06-11T16:49:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/41/e6/4eee3062088c221e5a18b054e51c69f616e0bb0dc1b0a1a5e0fe90dfa18e/clarabel-0.11.1-cp39-abi3-win_amd64.whl", hash = "sha256:557d5148a4377ae1980b65d00605ae870a8f34f95f0f6a41e04aa6d3edf67148", size = 887310, upload-time = "2025-06-11T16:49:04.277Z" }, +] + [[package]] name = "contourpy" version = "1.3.3" @@ -74,6 +137,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b9/55/90b40b489a235a9f35a532eb77cec81782e466779d9a531ffda6b2f99410/cvxopt-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:0a0987966009ad383de0918e61255d34ed9ebc783565bcb15470d4155010b6bf", size = 12845323, upload-time = "2024-10-21T20:49:00.581Z" }, ] +[[package]] +name = "cvxpy" +version = "1.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "clarabel" }, + { name = "numpy" }, + { name = "osqp" }, + { name = "scipy" }, + { name = "scs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/cf/583d8c25bf1ec8d43e0f9953fa3d48f095022dc2fc7e7a437ebdeaf16d9f/cvxpy-1.7.3.tar.gz", hash = "sha256:241d364f5962a1d68c4ae8393480766a09326e5771e2286d33a948e1976cbe70", size = 1635660, upload-time = "2025-09-22T18:21:42.245Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/9f/a66cd862fdcca0027a8b902079d6a2ce86848b9f38a1c6e80bfdc8f72964/cvxpy-1.7.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:052db7e5485d3cbe6b0249c4cc0fec898cdfafcb8d2490149a21bd9a7d00a82f", size = 1538061, upload-time = "2025-09-22T18:02:30.573Z" }, + { url = "https://files.pythonhosted.org/packages/b2/9f/0bf93d696e6e75ae42e40915abb38ecae4a3b27f6cb52765415b012fda70/cvxpy-1.7.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a97e4e3eff4e9f8151058fe7687c7eecfb44b6a1ae83834195b701088ce29e7", size = 1193747, upload-time = "2025-09-22T18:02:32.024Z" }, + { url = "https://files.pythonhosted.org/packages/48/55/1542a643403cd57adf83e27243dc2a057fb4fab03f38f5de3cb0327e468a/cvxpy-1.7.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cfed5afe3d53fc7835ea8cc9e281d0bbf3b4edcc625e8a1162c42cb807b8830d", size = 1204232, upload-time = "2025-09-22T18:22:27.222Z" }, + { url = "https://files.pythonhosted.org/packages/f8/bf/9b5b5abcf06038eea8826d440c5c24c1f32c7339c750f0b705d2fe4cdafc/cvxpy-1.7.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d8b2213296478478d267537681f96ea7d9941d5bb1fa61717797f9fabd3b747", size = 1233261, upload-time = "2025-09-22T18:22:28.709Z" }, + { url = "https://files.pythonhosted.org/packages/02/ca/4648ad361e0060834104672c2ce0d6a96996f374e83615fc69a87b1e3841/cvxpy-1.7.3-cp313-cp313-win_amd64.whl", hash = "sha256:d1def84c970a8a5765849e225732c6308c1bba8900bbfa7d4a17ea955e82ce80", size = 1131760, upload-time = "2025-09-22T18:01:04.595Z" }, +] + [[package]] name = "cycler" version = "0.12.1" @@ -173,6 +256,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/45/d8/55e0901103c93d57bab3b932294c216f0cbd49054187ce29f8f13808d530/jaxopt-0.8.5-py3-none-any.whl", hash = "sha256:ff221d1a86908ec759eb1e219ee1d12bf208a70707e961bf7401076fe7cf4d5e", size = 172434, upload-time = "2025-04-14T17:59:00.342Z" }, ] +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, +] + [[package]] name = "kiwisolver" version = "1.4.9" @@ -232,6 +336,58 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" }, ] +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + [[package]] name = "matplotlib" version = "3.10.7" @@ -285,6 +441,7 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "cvxopt" }, + { name = "cvxpy" }, { name = "jax" }, { name = "jaxopt" }, { name = "matplotlib" }, @@ -296,6 +453,7 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "cvxopt", specifier = ">=1.3.2" }, + { name = "cvxpy", specifier = ">=1.7.3" }, { name = "jax", specifier = ">=0.8.0" }, { name = "jaxopt", specifier = ">=0.8.5" }, { name = "matplotlib", specifier = ">=3.10.7" }, @@ -392,6 +550,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932, upload-time = "2024-09-26T14:33:23.039Z" }, ] +[[package]] +name = "osqp" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/cf/023078d9985526494901e9ca91c59d17b2d2e5f87a047f4b8b9749ce5922/osqp-1.0.5.tar.gz", hash = "sha256:60b484cf829c99d94bb7ae4e9beb2e0895d94c5e64e074b5b27b6ef887941936", size = 56757, upload-time = "2025-10-15T14:05:33.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/13/bd94ec700462989623891078cfe911a1331e83054575acc8b5f78dcd3e46/osqp-1.0.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:da8e109d679d1faf2ed1142cd0bacd70fab5c91a7109bd85a6b228d423124dcb", size = 328512, upload-time = "2025-10-15T14:05:16.482Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e5/b7402123c33ee690b39cfcf35ac4bc77c5f0e5506b33112073063cb1c02c/osqp-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b99d308b2a6be07fd02a3712f4885feff31114b3eff35e1e97bc0caba61032e7", size = 302175, upload-time = "2025-10-15T14:05:17.688Z" }, + { url = "https://files.pythonhosted.org/packages/3c/3d/ad5aaa20780fbdc3bb240f1688a015d9cf07bd955b74f3443147cea82ecb/osqp-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3e8de72c880ccabaefcbc8418378426d4ea2e6dc6fd3acbd96de00a605f94ad", size = 335030, upload-time = "2025-10-15T14:05:18.92Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/56b7039c43457cfa113842f8345bd346af03caf2af403e0a91d040abacdc/osqp-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f8910df4c2e419078961cd4e7a4d6e14ed0269f66a0f2f774a895fc14ef8ff", size = 357417, upload-time = "2025-10-15T14:05:20.022Z" }, + { url = "https://files.pythonhosted.org/packages/f2/df/46ca217567451b12acc7585be2ee43089846792ae0340ce93ab7e662b47a/osqp-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:0a90b8fee99daa00760bd336dd074731289690700d9e7eae3900db233f8bfa02", size = 310518, upload-time = "2025-10-15T14:05:21.029Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -465,6 +643,15 @@ version = "2.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a3/a6/b8e451f6cff1c99b4747a2f7235aa904d2d49e8e1464e0b798272aa84358/progressbar-2.5.tar.gz", hash = "sha256:5d81cb529da2e223b53962afd6c8ca0f05c6670e40309a7219eacc36af9b6c63", size = 10046, upload-time = "2018-06-29T02:32:00.222Z" } +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + [[package]] name = "pyparsing" version = "3.2.5" @@ -537,6 +724,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, ] +[[package]] +name = "scs" +version = "3.2.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0c/c0/b894547702586a252f8c417e0c77111c9d2ae1d69c4a7751eb505e4fdb62/scs-3.2.9.tar.gz", hash = "sha256:df9542d435d21938ed09494a6c525a9772779902b61300961e16890a2df7f572", size = 1690742, upload-time = "2025-10-12T20:20:21.489Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/47/cf86c988b341dd1dd59661f29b87756ccd67952c706937257b51775c0251/scs-3.2.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6b585d33069829a16ef80bedd976fc6eee6e1287324f218ef6995f40e84a4566", size = 95653, upload-time = "2025-10-12T20:19:45.992Z" }, + { url = "https://files.pythonhosted.org/packages/2a/38/eb3b2d98aa5a24e6b4752520c220568e065809d02707336756e602dbdd93/scs-3.2.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c372807c261f3791b21b83d0a631f2a3bb79b73f16d9087dc289ea90560f59b1", size = 5069833, upload-time = "2025-10-12T20:19:47.056Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ef/26238d2f0e851ffbb73d0c34c5b59245229af6c8b979a959fda9ab5278ca/scs-3.2.9-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9835c50081dfc270735fe339cced27ce2818383ea779fc6c673c885b0cdf849f", size = 12078832, upload-time = "2025-10-12T20:19:49.112Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b8/b29c2813487c8718c679db2986ef27b13d4169696dd084ffab110cb34060/scs-3.2.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5188d3b77f618c321bcb9486a0864e39dea2774d8a52ed9b8355d7dc42f5ee77", size = 11972927, upload-time = "2025-10-12T20:19:51.153Z" }, + { url = "https://files.pythonhosted.org/packages/ea/02/97813588bd4cb26f45c293899dd2834e25b019724a390e1a224c4f128396/scs-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:6c75f835df827e8a9e1c19668fa4b21d4b7047017d19ceab4e98db2506acc466", size = 7458828, upload-time = "2025-10-12T20:19:52.98Z" }, + { url = "https://files.pythonhosted.org/packages/7c/8f/cf5e0414e2dfcd2fea25b6653ae1f94dc3221d0df6d0ddd3e345f1930039/scs-3.2.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f34aa0fb3776b546e4d3346a367fe32b72f9b5b302ec42cbb6ba157ee987f566", size = 95682, upload-time = "2025-10-12T20:19:54.375Z" }, + { url = "https://files.pythonhosted.org/packages/5d/d2/bc9b66c50d3bbec7bd51d78261d6b79ef02be170e8694b303efea79d7956/scs-3.2.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f884952d4faf9b9e7bdaa19b9b9563955c8e27f37fdf271354e2eb28d98bac0", size = 5069860, upload-time = "2025-10-12T20:19:55.723Z" }, + { url = "https://files.pythonhosted.org/packages/cc/7b/55bdd5f88e3abdee29bcae2a2dad907bdcac24ec79f005d372abae551e6a/scs-3.2.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f25e461f52d7d3128583a64ac8b724b976b7e18bc1f04ae98b3b75a5c11a7e2", size = 12078906, upload-time = "2025-10-12T20:19:57.78Z" }, + { url = "https://files.pythonhosted.org/packages/db/f9/036942285ea56febea84149aae7aed28451d0d7727af31f951da9beee6a5/scs-3.2.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0667f1ec3f4c141ee877531ef2e4568b82633b8a41de29c8341279d7e8e7ef5c", size = 11972938, upload-time = "2025-10-12T20:19:59.814Z" }, + { url = "https://files.pythonhosted.org/packages/03/76/3733c2bf1c2022d6bad92ed2a0146e2129ef992afa87708d20b1b36c5a1d/scs-3.2.9-cp314-cp314-win_amd64.whl", hash = "sha256:feb0a7e29bd26285270a9882d1bdd4b1e981a4e9cdb8eaee5f967a47bb2882ff", size = 7549101, upload-time = "2025-10-12T20:20:02.122Z" }, + { url = "https://files.pythonhosted.org/packages/a5/1a/e6a1049e741a541a675f37424aaa6461476ab5c3833858b87437154dc87a/scs-3.2.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d8573e25bc85ef77ba43bb849b4a771aeb9eb1ad43497aa181d773cc543e9a39", size = 96375, upload-time = "2025-10-12T20:20:03.444Z" }, + { url = "https://files.pythonhosted.org/packages/58/e3/9ada9f242906c0abc642e3e70cb4b65f311bdaadfb83fbd063b581a7c7b6/scs-3.2.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d02756334b2263c7514604910000bffc016e148ef9a5a8eeeaaf52ec66f506", size = 5070943, upload-time = "2025-10-12T20:20:04.824Z" }, + { url = "https://files.pythonhosted.org/packages/36/75/c11551cebba8f36ce46a32cdc71c808b03aeb601c441fc194fe31d526ab4/scs-3.2.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4328aa741df45b3632253028f516d73f77081f372f90cdefeb3b94f4f7504ea4", size = 12079147, upload-time = "2025-10-12T20:20:06.266Z" }, + { url = "https://files.pythonhosted.org/packages/0d/94/c659c0442b0386bca295f7d5e8bae1b59af12d29370bd590b00cc2ddf730/scs-3.2.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1e786a28f942f5b0b5a28af552a6cb882b366cee4b9271267d147796d71e60d0", size = 11973255, upload-time = "2025-10-12T20:20:08.212Z" }, + { url = "https://files.pythonhosted.org/packages/27/d4/752ee94d27a400199b6fd952fe5f0253ae4b9eff565b3c6476fa6378f827/scs-3.2.9-cp314-cp314t-win_amd64.whl", hash = "sha256:23577f318d25cd623fedbe7f3330189f6d5f82c855db08e3b32bf77f43efdc4b", size = 7549595, upload-time = "2025-10-12T20:20:11.209Z" }, +] + +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + [[package]] name = "six" version = "1.17.0" From 7208ad554d3b745453c9f5c2ac41e362a34533c6 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 7 Nov 2025 19:20:44 +0000 Subject: [PATCH 16/52] lets try be tidy --- .gitignore | 42 +++++++++++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 14 ++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5d6484 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Sphinx documentation +docs/_build/ + +# Jupyter Notebook +.ipynb_checkpoints + +# OS +.DS_Store \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ea79323 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,14 @@ +repos: + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.12.9 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format + args: [--line-length=79] + + - repo: https://github.com/pycqa/isort + rev: 6.0.1 + hooks: + - id: isort + args: ["--profile", "black"] \ No newline at end of file From 9594171dbe5ad751ed975d7286a619c73b14e315 Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 15:47:34 +0000 Subject: [PATCH 17/52] adding ruff stuff to the pyproject.toml --- pyproject.toml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index e927bf0..12a54ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,3 +14,18 @@ dependencies = [ "progressbar>=2.5", "scipy>=1.16.3", ] + + +[tool.ruff] +line-length = 79 + +[tool.ruff.lint] +select =["E", "F", "W", # basics + "I", # isort + "D", # docstrings + "UP", # pyupgrade (includes type modernization) + "ANN", # type annotations + ] + +[tool.ruff.lint.pydocstyle] +convention = "google" From a936bd21af9d506d6b6667e83ebef9aaf3bef4c6 Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 16:34:20 +0000 Subject: [PATCH 18/52] formatting the models functions a bit better --- maxsmooth/models.py | 250 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 228 insertions(+), 22 deletions(-) diff --git a/maxsmooth/models.py b/maxsmooth/models.py index dfdcaab..82673a0 100755 --- a/maxsmooth/models.py +++ b/maxsmooth/models.py @@ -1,80 +1,286 @@ -from jax import numpy as jnp +"""Various functional forms for modeling data.""" + import jax +from jax import numpy as jnp + @jax.jit -def normalised_polynomial(x, norm_x, norm_y, params): +def normalised_polynomial( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate a normalised polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated polynomial at x. + """ i = jnp.arange(params.shape[0]) - powers = (x / norm_x) ** i + powers = (x / norm_x) ** i y_sum = norm_y * jnp.sum(params * powers, axis=0) return y_sum + @jax.jit -def normalised_polynomial_basis(x, norm_x, norm_y, params): +def normalised_polynomial_basis( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate the basis functions of a normalised polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated basis functions at x. + """ i = jnp.arange(params.shape[0]) - powers = norm_y * (x / norm_x) ** i + powers = norm_y * (x / norm_x) ** i return powers + @jax.jit -def polynomial(x, norm_x, norm_y, params): +def polynomial( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate a polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated polynomial at x. + """ i = jnp.arange(params.shape[0]) - powers = x ** i + powers = x**i y_sum = jnp.sum(params * powers, axis=0) return y_sum + @jax.jit -def polynomial_basis(x, norm_x, norm_y, params): +def polynomial_basis( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate the basis functions of a polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated basis functions at x. + """ i = jnp.arange(params.shape[0]) - powers = x ** i + powers = x**i return powers + @jax.jit -def loglog_polynomial(x, norm_x, norm_y, params): +def loglog_polynomial( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate a log-log polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated polynomial at x. + """ i = jnp.arange(params.shape[0]) powers = jnp.log10(x) ** i - y_sum = 10**jnp.sum(params * powers, axis=0) + y_sum = 10 ** jnp.sum(params * powers, axis=0) return y_sum + @jax.jit -def loglog_polynomial_basis(x, norm_x, norm_y, params): +def loglog_polynomial_basis( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate the basis functions of a log-log polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated basis functions at x. + """ i = jnp.arange(params.shape[0]) - powers = jnp.log10(x) ** i + powers = jnp.log10(x) ** i return powers + @jax.jit -def exponential(x, norm_x, norm_y, params): +def exponential( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate an exponential basis at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the exponential basis. + + Returns: + jnp.ndarray: Evaluated exponential basis at x. + """ i = jnp.arange(params.shape[0]) powers = jnp.exp(-i * x / norm_x) y_sum = norm_y * jnp.sum(params * powers, axis=0) return y_sum + @jax.jit -def exponential_basis(x, norm_x, norm_y, params): +def exponential_basis( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate the basis functions of an exponential basis at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the exponential basis. + + Returns: + jnp.ndarray: Evaluated basis functions at x. + """ i = jnp.arange(params.shape[0]) powers = norm_y * jnp.exp(-i * x / norm_x) return powers + @jax.jit -def log_polynomial(x, norm_x, norm_y, params): +def log_polynomial( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate a log polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated polynomial at x. + """ i = jnp.arange(params.shape[0]) powers = jnp.log10(x / norm_x) ** i y_sum = jnp.sum(params * powers, axis=0) return y_sum + @jax.jit -def log_polynomial_basis(x, norm_x, norm_y, params): +def log_polynomial_basis( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate the basis functions of a log polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated basis functions at x. + """ i = jnp.arange(params.shape[0]) - powers = jnp.log10(x / norm_x) ** i + powers = jnp.log10(x / norm_x) ** i return powers + @jax.jit -def difference_polynomial(x, norm_x, norm_y, params): +def difference_polynomial( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate a difference polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated polynomial at x. + """ i = jnp.arange(params.shape[0]) powers = (x - norm_x + 1e-6) ** i y_sum = jnp.sum(params * powers, axis=0) return y_sum + @jax.jit -def difference_polynomial_basis(x, norm_x, norm_y, params): +def difference_polynomial_basis( + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, +) -> jnp.ndarray: + """Evaluate the basis functions of a difference polynomial at x. + + Args: + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Coefficients of the polynomial. + + Returns: + jnp.ndarray: Evaluated basis functions at x. + """ i = jnp.arange(params.shape[0]) - powers = (x - norm_x + 1e-6) ** i - return powers \ No newline at end of file + powers = (x - norm_x + 1e-6) ** i + return powers From 6be14ac67fa2fa334f6c3cc9b55523f09a261b67 Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 16:36:30 +0000 Subject: [PATCH 19/52] adding some doc strings and formatting --- maxsmooth/qp.py | 124 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 87 insertions(+), 37 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index 6c13647..3405fa7 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -1,87 +1,137 @@ -from maxsmooth.derivatives import derivative_prefactors -from maxsmooth.utils import is_positive_definite_cholesky -from jaxopt import OSQP, CvxpyQP -from jax import numpy as jnp +"""Quadratic programming call for maxsmooth.""" + +from collections.abc import Callable from itertools import product + import jax +import jaxopt +from jax import numpy as jnp +from jaxopt import OSQP, CvxpyQP +from maxsmooth.derivatives import derivative_prefactors -def qp(x, y, N, pivot_point, function, basis_function, solver='OSQP'): +def qp( + x: jnp.ndarray, + y: jnp.ndarray, + N: int, + pivot_point: int, + function: Callable, + basis_function: Callable, + solver: str = "OSQP", +) -> dict: + """Set up and solve the quadratic programming problem for maxsmooth. + + Args: + x (jnp.ndarray): Input data points. + y (jnp.ndarray): Output data points. + N (int): Number of basis functions. + pivot_point (int): Index of the pivot point. + function (Callable): The model funciton from `maxsmooth.models`. + basis_function (Callable): The basis function to use. + solver (str, optional): Solver to use ('OSQP' or 'CvxpyQP'). + Defaults to 'OSQP'. + + Returns: + dict: Dictionary containing solver information and solution. + """ # needs some dummy parameters to make basis - basis = jax.vmap(basis_function, in_axes=(0, None, None, None)) \ - (x, x[pivot_point], y[pivot_point], jnp.ones(N)) + basis = jax.vmap(basis_function, in_axes=(0, None, None, None))( + x, x[pivot_point], y[pivot_point], jnp.ones(N) + ) Q = jnp.dot(basis.T, basis) - #regularization = 1e-6 * jnp.eye(N) # Small regularization term - #Q = Q + regularization - - check = is_positive_definite_cholesky(Q) - print("Is Q positive definite?", check) c = -jnp.dot(basis.T, y) - G = derivative_prefactors(function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N) + G = derivative_prefactors( + function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N + ) G = G[2:] G_scaled = [] for i, g in enumerate(G): # square root of sum of squares of each row g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) - g_norm = jnp.where(g_norm < 1e-10, 1.0, g_norm) # Avoid division by zero + g_norm = jnp.where( + g_norm < 1e-10, 1.0, g_norm + ) # Avoid division by zero G_scaled.append(g / g_norm) G = G_scaled - - print("Q shape:", Q.shape) - print("c shape:", c.shape) - print("G[0] shape:", G[0].shape, len(G)) - - # All possible sign combinations for the blocks of G all_signs = list(product((-1.0, 1.0), repeat=len(G))) - print(f"Total sign combinations: {len(all_signs)}") all_signs = jnp.array(all_signs) - #init_params = jnp.linalg.solve(Q, -c) + # init_params = jnp.linalg.solve(Q, -c) - if solver == 'OSQP': + if solver == "OSQP": qp = OSQP(maxiter=10000, tol=1e-3) + @jax.jit - def dcf(signs, c, Q): - - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + def dcf( + signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray + ) -> jaxopt._src.base.OptStep: + """Run the quadratic programming using jaxopt OSQP. + + Args: + signs (jnp.ndarray): Sign combination + for the inequality constraints. + c (jnp.ndarray): Linear term in the objective function. + Q (jnp.ndarray): Quadratic term in the objective function. + + Returns: + sol: Solution of the quadratic programming problem. + """ + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) h = jnp.zeros(Gmat.shape[0]) - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h))#.params - + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) # .params return sol vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) # Solve all QPs sol = vmapped_dcf(all_signs, c, Q) - if solver == 'CvxpyQP': + if solver == "CvxpyQP": qp = CvxpyQP() + def dcf_cvxpyqp( + signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray + ) -> jaxopt._src.base.OptStep: + """Run the quadratic programming using Cvxpy. + + Args: + signs (jnp.ndarray): Sign combination for the + inequality constraints. + c (jnp.ndarray): Linear term in the objective function. + Q (jnp.ndarray): Quadratic term in the objective function. - def dcf_cvxpyqp(signs, c, Q): + Returns: + sol: Solution of the quadratic programming problem. + """ Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) h = jnp.zeros(Gmat.shape[0]) - + # Convert to numpy for cvxpy Q_np = jnp.array(Q) c_np = jnp.array(c) Gmat_np = jnp.array(Gmat) h_np = jnp.array(h) - - sol = qp.run(init_params=jnp.ones(N), params_obj=(Q_np, c_np), params_ineq=(Gmat_np, h_np)) + + sol = qp.run( + init_params=jnp.ones(N), + params_obj=(Q_np, c_np), + params_ineq=(Gmat_np, h_np), + ) return sol # Use a regular loop instead of vmap solutions = [] - print(f"Solving {len(all_signs)} QPs...") for i, signs in enumerate(all_signs): - if i % 4 == 0: # Progress indicator - print(f" Progress: {i}/{len(all_signs)}") sol = dcf_cvxpyqp(signs, c, Q) solutions.append(sol) sol = solutions.copy() - return {'solver': solver, 'state': sol.state, 'params': sol.params.primal, 'sol': sol} \ No newline at end of file + return { + "solver": solver, + "state": sol.state, + "params": sol.params.primal, + "sol": sol, + } From 00109af019d637aa858034042d4cfff6825ef2d5 Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 16:39:12 +0000 Subject: [PATCH 20/52] removing some examples --- example_codes/Data/x.npy | Bin 928 -> 0 bytes example_codes/Data/y.npy | Bin 928 -> 0 bytes example_codes/param_plotter_example.py | 84 ------------------------- 3 files changed, 84 deletions(-) delete mode 100755 example_codes/Data/x.npy delete mode 100755 example_codes/Data/y.npy delete mode 100644 example_codes/param_plotter_example.py diff --git a/example_codes/Data/x.npy b/example_codes/Data/x.npy deleted file mode 100755 index 8e1e3924f227d9142db6e33f862b417ff445cba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 928 zcmbW0`Abw$6vwSF%NC`D5;G^UM$Jky#7g8FWw^~a`#$sDn;ezWG!;WL#SB9evou;v zG%IPrtU!t=QZOp9P0UcURobJXg(#BFo%!Rn7$cTvW&~VvK*?*U} zhr1FH?z#DIQh6dw-UGi6PE5jXpSWMoE0SxDv%)C@~gO`zoeZ3124TlZx2&&Zqb4Qu)29D)cUC z%(|4Q;`ggn__>q}^s2bdG&O=Eb21WA)LgGd4Q2FDTK!!$*PW?B@mdm8YPkMB4cgEy zgg(&lKE7J?$Ir7DsI|yU=o|4npv8Dnx#dQ`77Yp#nyo_^v#ryiOVcvg(V&AtPxVNL zk46G8SC3tm8=4k_9`o%5591H%abBQ7AM3G!jWOSV;k0^1wAp~%3~F%1fXNKsumQ)i zF5Ow;Z^TNn-)A-A_O=DLwjDFVK{E43jrd+z*>f$xgz6$1z+r+LXR`^NrKiyT%!FjJ zsgarSqJkD6nz5ZeZ#r(qj4HbD(u@;(33QMJs~O%+7Tm8pd^zf*1un8PG-kn{gA+ST z7hAEPj)T*!kQ3%RZB|@wS`?Y{#tJQsJ14}3cdaCpX+s&c70%c&m#z7|4d>2Mh1s!= zaH_W0@wkHmaL$fw8msZ69g~>RWeyx6`PbPFtYB+D@4(G#)ZnuNR>C&8LcrH^_Rd> z7#J&YzBUOgojoNI=iDTLjkEc>#CeZOaK~_5;@lTH!BXBC=j8kaC)oNdWlp|_W+&Xg IMVAx*0O&4yg#Z8m diff --git a/example_codes/Data/y.npy b/example_codes/Data/y.npy deleted file mode 100755 index b648c7ccd01868de350bc22ce53a50811116eccc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 928 zcmbWraZ?fo0Eb~&O|5iV-E}mbBG!E^C=x#l^`+ftL;GMAtw-c4Ixc(T>B?sV-d?EUY3+KwE{$~i&sk@!?m z3R$88AtjMSNn#(M&`1a1#>O?PrF`k0ras0k)m_Rb}!vjOq@k(4uNmD)r{XtRl(ohZo-}W z^vug!lCL*=Jn6ySM?#az*1Un+|J>XB_$`TJ+9R zdI)qa0w07*f6~`O9(3QI`-cV(!V+S;(=?dL`yq2juNu))n-P=WZnP3>vBwq94Zo~}DI||>{XmIF;)`>S zZ8eaEzRj3(Rio8D#=J+YMuKY9BFa->C30FOv44h2nzFF{c@-$eUzAOmRXCVzVuxRr z2D_I^5MBRWz^o}q4o}EZ83_6)0y_Rh>kMY8PV3A zfo0%LXZKjtrJx@QQeN69!G-P1WdG_Cs12qYS2wuW@z;?$xtfau!RsTr0bDpVVdIhK ziy;?Pph!jFp37nM^K@sI;??6w$|go9Hb<}8M6=fL?Ir6;bJ Gjeh}D^pM~H diff --git a/example_codes/param_plotter_example.py b/example_codes/param_plotter_example.py deleted file mode 100644 index 6f20709..0000000 --- a/example_codes/param_plotter_example.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -We can assess the parameter space around the optimum solution -found using ``maxsmooth`` with the param_plotter() function. -This can help us identify how well a problem can be solved using the -sign sampling approach employed by ``maxsmooth`` or simply -be used to identify correlations between the foreground parameters. -For more details on this see the ``maxsmooth`` paper. - -We begin by importing and fitting the data as with the chi_plotter() -function illustrated above. -""" - -import numpy as np - -x = np.load('Data/x.npy') -y = np.load('Data/y.npy') - -from maxsmooth.DCF import smooth - -N = 5 -result = smooth(x, y, N, base_dir='examples/', fit_type='qp') - -""" -We have changed the order of the fit to 5 to illustrate that for -order :math:`{N \leq 5}` and fits with derivatives :math:`{m \geq 2}` constrained -the function will plot each region of the graph corresponding to -different sign functions in a different colourmap. If the constraints are -different or the order is greater than 5 then the viable regions will have -a single colourmap. Invalid regions are plotted as black shaded colourmaps -and the contour lines are contours of :math:`{\chi^2}`. - -Specifically, invalid regions violate the condition - -.. math:: - - \pm_m \frac{\delta^m y}{\delta x^m} \leq 0 - -where :math:`{m}` represents the derivative order, :math:`{y}` is the dependent -variable and :math:`{x}` is the independent variable. Violation of the -condition means that one or more of the constrained derivatives crosses 0 in the -band of interest. For an MSF, as mentioned, :math:`{m \geq 2}` and the sign :math:`{\pm_m}` -applies to specific derivative orders. For this specific example there are -3 constrained derivatives, :math:`{m = 2, 3, 4}` and consequently 3 signs to -optimise for alongside the parameters :math:`{a_k}`. The coloured valid regions -therefore correspond to a specific combination of :math:`{\pm_m}` for the problem. -:math:`{\pm_m}` is also referred to as :math:`{\mathbf{s}}` in the theory -section and the ``maxsmooth`` paper. - -We can import the function like so, -""" - -from maxsmooth.parameter_plotter import param_plotter - -""" -and access it using, -""" - -param_plotter(result.optimum_params, result.optimum_signs, - x, y, N, base_dir='examples/') - -""" -The function takes in the optimum parameters and signs found after the fit -as well as the data and order of the fit. There are a number of keyword arguments -detailed in the following section and the resultant fit is shown below. The -function by default samples the parameter ranges 50% either side of the optimum -and calculates 50 spamples for each parameter. In each panel the two -labelled parameters are varied while the others are maintained at their optimum -values. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/Parameter_plot.png - -We are also able to plot the data, fit and residuals alongside the parameter -plot and this can be done by setting data_plot=True. We can also highlight the -central region in each panel of the parameter space by setting center_plot=True. -""" - -param_plotter(result.optimum_params, result.optimum_signs, - x, y, N, base_dir='examples/', data_plot=True, center_plot=True) - -""" -which gives us the graph below. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/Parameter_plot_extended.png -""" From c3ed22e9728c7131832527e30d71b6bc72ec8203 Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 16:45:26 +0000 Subject: [PATCH 21/52] comments to the derivatives functions --- maxsmooth/derivatives.py | 54 +++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/maxsmooth/derivatives.py b/maxsmooth/derivatives.py index d0617a1..f7806f2 100755 --- a/maxsmooth/derivatives.py +++ b/maxsmooth/derivatives.py @@ -1,21 +1,63 @@ +"""Compute derivative prefactors for a given function using JAX.""" + +from collections.abc import Callable + import jax +import jax.numpy as jnp + # function to generate derivatives -def make_derivative_functions(f, max_order): - derivs = [f] - for n in range(1, max_order): +def make_derivative_functions(f: Callable, max_order: int) -> list[Callable]: + """Return list of functions computing derivatives of f up to max_order. + + Args: + f (Callable): Function to differentiate. + max_order (int): Maximum order of derivatives to compute. + + Returns: + List[Callable]: List of derivative functions. + """ + derivs = [f] + for _ in range(1, max_order): derivs.append(jax.grad(derivs[-1], argnums=0)) return derivs -def derivative_prefactors(f, x, norm_x, norm_y, params, max_order): + +def derivative_prefactors( + f: Callable, + x: jnp.ndarray, + norm_x: jnp.ndarray, + norm_y: jnp.ndarray, + params: jnp.ndarray, + max_order: int, +) -> list[jnp.ndarray]: + """Return list of derivative matrices G[m]. + + G[m] maps params -> m-th derivative at all x. + + Args: + f (Callable): Function to differentiate. + x (jnp.ndarray): Input data points. + norm_x (jnp.ndarray): Normalisation point for x. + norm_y (jnp.ndarray): Normalisation point for y. + params (jnp.ndarray): Parameters of the function. + max_order (int): Maximum order of derivatives to compute. + + Returns: + List[jnp.ndarray]: List of derivative matrices. + """ Gs = [] df_dx = f # start from f for m in range(max_order): # Jacobian of current derivative w.r.t parameters - Gm = jax.vmap(lambda xi: jax.jacobian(df_dx, argnums=3)(xi, norm_x, norm_y, params))(x) + Gm = jax.vmap( + lambda xi: jax.jacobian(df_dx, argnums=3)( + xi, norm_x, norm_y, params + ) + )(x) Gs.append(Gm) # Prepare next derivative wrt x df_dx = jax.grad(df_dx, argnums=0) - return Gs \ No newline at end of file + return Gs From e70073240e5993f6a6b360a3c011fba5e0db96fb Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 16:48:22 +0000 Subject: [PATCH 22/52] adding a version file --- maxsmooth/_version.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 maxsmooth/_version.py diff --git a/maxsmooth/_version.py b/maxsmooth/_version.py new file mode 100644 index 0000000..8c0d5d5 --- /dev/null +++ b/maxsmooth/_version.py @@ -0,0 +1 @@ +__version__ = "2.0.0" From 11ed33cfc1ca217300e8b35c1e77f5c4fd990677 Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 16:59:36 +0000 Subject: [PATCH 23/52] bumping python version numbers but this actually needs some tidying as well --- .github/workflows/CI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 4959dfa..04d12fb 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] + python-version: ["3.9", "3.10", "3.12", "3.13"] steps: - uses: actions/checkout@v2 From fe0d90133229a04214b94a55067a5513fc706851 Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 17:03:13 +0000 Subject: [PATCH 24/52] linitng workflow with ruff and CI install from pyproject.toml --- .github/workflows/CI.yml | 10 ++-------- .github/workflows/lint.yml | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 04d12fb..ec8152b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -26,14 +26,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install flake8 pytest coverage - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + python -m pip install pytest coverage + pip install -e . - name: Test with pytest run: | coverage run --source=maxsmooth -m py.test diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..57cc901 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,26 @@ +name: Lint + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install tools + run: | + pip install "ruff==0.12.9" "isort==6.0.1" + + - name: Run Ruff (check mode) + run: ruff check . \ No newline at end of file From bb6da3bb9ca44c9c31de0678f3fecb6b5a1beece Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 17:05:28 +0000 Subject: [PATCH 25/52] adding version check workflow --- .github/workflows/version_checks.yaml | 18 ++++ bin/check_version.py | 130 ++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 .github/workflows/version_checks.yaml create mode 100644 bin/check_version.py diff --git a/.github/workflows/version_checks.yaml b/.github/workflows/version_checks.yaml new file mode 100644 index 0000000..f3c2eae --- /dev/null +++ b/.github/workflows/version_checks.yaml @@ -0,0 +1,18 @@ +name: Version_Checks + +on: + pull_request: + branches: [master] + +jobs: + version-checks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + - name: Upgrade pip and install linters + run: | + python -m pip install --upgrade pip + python -m pip install packaging + - name: Check version number + run: python ./bin/check_version.py \ No newline at end of file diff --git a/bin/check_version.py b/bin/check_version.py new file mode 100644 index 0000000..996d4e5 --- /dev/null +++ b/bin/check_version.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +"""Check Version. + +Verify version has been incremented. + +Based on check_version.py from the anesthetic GitHub repository: +https://github.com/handley-lab/anesthetic +""" + +import subprocess +import sys + +from packaging import version + +# Filestructure +readme_file = "README.rst" + + +# Utility functions +def run_on_commandline(*args): + """Run the given arguments as a command on the command line.""" + return subprocess.run( + args, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ).stdout + + +def unit_incremented(version_a: str, version_b: str) -> bool: + """Check if version_a is one version larger than version_b. + + Parameters + ---------- + version_a: str + New version, version number + version_b: str + Old version, version number + + Returns: + ------- + unit_incremented: bool + Whether, version number has been unit incremented + """ + # Convert to version objects + version_a = version.parse(version_a) + version_b = version.parse(version_b) + + # Check increment for pre-release versions + if version_a.pre is not None and version_b.pre is not None: + # Matching pre-release levels + if version_a.pre[0] == version_b.pre[0]: + return (version_a.pre[1] == (int(version_b.pre[1]) + 1)) and ( + version_a.base_version == version_b.base_version + ) + # Differing pre-release levels + else: + return ( + version_a.pre[1] == 0 + and version_a.pre[0] > version_b.pre[0] + and version_a.base_version == version_b.base_version + ) + + # New pre-release level + elif version_a.pre is not None: + return ( + version_a.base_version > version_b.base_version + and version_a.pre[1] == 0 + ) + + # Full release + elif version_b.pre is not None: + return version_a.base_version == version_b.base_version + + # Standard version major, minor and micro increments + else: + return ( + version_a.micro == version_b.micro + 1 + and version_a.minor == version_b.minor + and version_a.major == version_b.major + or version_a.micro == 0 + and version_a.minor == version_b.minor + 1 + and version_a.major == version_b.major + or version_a.micro == 0 + and version_a.minor == 0 + and version_a.major == version_b.major + 1 + ) + + +def get_current_version() -> str: + """Get current version of package from README.rst""" + current_version = run_on_commandline("grep", ":Version:", readme_file) + current_version = current_version.split(":")[-1].strip() + return current_version + + +def main(): + """Check version is consistent and incremented correctly.""" + # Get current version from readme + current_version = get_current_version() + + # Get previous version from main branch of code + run_on_commandline("git", "fetch", "origin", "master") + readme_contents = run_on_commandline( + "git", "show", "remotes/origin/master:" + readme_file + ) + + previous_version = None + for line in readme_contents.splitlines(): + if ":Version:" in line: + previous_version = line.split(":")[-1].strip() + break + + if previous_version is None: + raise ValueError( + "Could not find version in README.rst on master branch" + ) + + # Check versions have been incremented + if not unit_incremented(current_version, previous_version): + sys.stderr.write( + "Version must be incremented by one:\n" + f"HEAD: {current_version},\n" + f"master: {previous_version}.\n" + ) + sys.exit(1) + + # No issues found, exit happily :) + sys.exit(0) + + +if __name__ == "__main__": + main() From 62010fc35d24192cc2ca4964d12afdbc3a3c927c Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 17:08:02 +0000 Subject: [PATCH 26/52] contribution guidelines and pull request template --- .github/CONTRIBUTING.md | 19 +++++++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 12 ++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..d1e596c --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,19 @@ +Contributions are welcome! + +If you have a new feature/bug report, make sure you create an [issue](https://github.com/htjb/margarine/issues), and consult existing ones first, in case your suggestion is already being addressed. + +If you want to go ahead and create the feature yourself, you should fork the repository to you own github account and create a new branch with an appropriate name. Commit any code modifications to that branch, push to GitHub, and then create a pull request via your forked repository. + +## Contributing - `pre-commit` + +To try and maintain a consistent style the code base is using pre-commit, ruff and isort. If you are ready to contribute to `margarine` please follow the instructions below before making a PR. + +First, ensure that pre-commit is installed: +``` +pip install pre-commit +``` +Then install the pre-commit to the .git folder: +``` +pre-commit install +``` +Before running `git commit` you should run `pre-commit run --files your_file` on any additional or changed files. This will check the code against ruff and isort and make any appropriate changes. \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..603d467 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +# Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context and describe the tests that have been added (if any). + +Fixes # (issue) + +# Checklist: + +- [ ] I have performed a self-review of my own code +- [ ] New and existing unit tests pass locally with my changes (`python -m pytest`) +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] I have appropriately incremented the [semantic version number](https://semver.org/) in both README.rst and maxsmooth/_version.py From 008afcccd11c542b01d28ec4e0d0c5beb816d25c Mon Sep 17 00:00:00 2001 From: htjb Date: Mon, 1 Dec 2025 17:13:04 +0000 Subject: [PATCH 27/52] margarine -> maxsmooth --- .github/CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d1e596c..cf2a912 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,12 +1,12 @@ Contributions are welcome! -If you have a new feature/bug report, make sure you create an [issue](https://github.com/htjb/margarine/issues), and consult existing ones first, in case your suggestion is already being addressed. +If you have a new feature/bug report, make sure you create an [issue](https://github.com/htjb/maxsmooth/issues), and consult existing ones first, in case your suggestion is already being addressed. If you want to go ahead and create the feature yourself, you should fork the repository to you own github account and create a new branch with an appropriate name. Commit any code modifications to that branch, push to GitHub, and then create a pull request via your forked repository. ## Contributing - `pre-commit` -To try and maintain a consistent style the code base is using pre-commit, ruff and isort. If you are ready to contribute to `margarine` please follow the instructions below before making a PR. +To try and maintain a consistent style the code base is using pre-commit, ruff and isort. If you are ready to contribute to `maxsmooth` please follow the instructions below before making a PR. First, ensure that pre-commit is installed: ``` @@ -16,4 +16,4 @@ Then install the pre-commit to the .git folder: ``` pre-commit install ``` -Before running `git commit` you should run `pre-commit run --files your_file` on any additional or changed files. This will check the code against ruff and isort and make any appropriate changes. \ No newline at end of file +Before running `git commit` you should run `pre-commit run --files your_file` on any additional or changed files. This will check the code against ruff and isort and make any appropriate changes. From 406501063530a5ce582c32bee190610a1b41aa0e Mon Sep 17 00:00:00 2001 From: htjb Date: Tue, 2 Dec 2025 09:38:50 +0000 Subject: [PATCH 28/52] adding a template function for the sign flipping function --- maxsmooth/qp.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index 3405fa7..f10cd54 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -135,3 +135,32 @@ def dcf_cvxpyqp( "params": sol.params.primal, "sol": sol, } + +def fastqpsearch( + x: jnp.ndarray, + y: jnp.ndarray, + N: int, + pivot_point: int, + function: Callable, + basis_function: Callable, + solver: str = "OSQP", +) -> dict: + """Set up and solve the quadratic programming problem for maxsmooth. + + fastqpsearch uses the searching algorithm detailed in the maxsmooth + paper to reduce the number of QP solves needed. + + Args: + x (jnp.ndarray): Input data points. + y (jnp.ndarray): Output data points. + N (int): Number of basis functions. + pivot_point (int): Index of the pivot point. + function (Callable): The model funciton from `maxsmooth.models`. + basis_function (Callable): The basis function to use. + solver (str, optional): Solver to use ('OSQP' or 'CvxpyQP'). + Defaults to 'OSQP'. + + Returns: + dict: Dictionary containing solver information and solution. + """ + return NotImplementedError("fastqpsearch is not implemented yet.") \ No newline at end of file From 64c30604545958970cdd1aee40c2eceed45d0d26 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 3 Dec 2025 15:02:52 +0000 Subject: [PATCH 29/52] some updates to make these things a bit quicker --- maxsmooth/qp.py | 103 +++++++++++++----------------------------------- qptesting.py | 77 +++++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 102 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index 3405fa7..f4b4686 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -6,7 +6,7 @@ import jax import jaxopt from jax import numpy as jnp -from jaxopt import OSQP, CvxpyQP +from jaxopt import OSQP from maxsmooth.derivatives import derivative_prefactors @@ -18,7 +18,6 @@ def qp( pivot_point: int, function: Callable, basis_function: Callable, - solver: str = "OSQP", ) -> dict: """Set up and solve the quadratic programming problem for maxsmooth. @@ -29,8 +28,6 @@ def qp( pivot_point (int): Index of the pivot point. function (Callable): The model funciton from `maxsmooth.models`. basis_function (Callable): The basis function to use. - solver (str, optional): Solver to use ('OSQP' or 'CvxpyQP'). - Defaults to 'OSQP'. Returns: dict: Dictionary containing solver information and solution. @@ -46,7 +43,7 @@ def qp( function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N ) G = G[2:] - G_scaled = [] + """G_scaled = [] for i, g in enumerate(G): # square root of sum of squares of each row g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) @@ -54,83 +51,39 @@ def qp( g_norm < 1e-10, 1.0, g_norm ) # Avoid division by zero G_scaled.append(g / g_norm) - G = G_scaled + G = G_scaled""" all_signs = list(product((-1.0, 1.0), repeat=len(G))) all_signs = jnp.array(all_signs) - # init_params = jnp.linalg.solve(Q, -c) - - if solver == "OSQP": - qp = OSQP(maxiter=10000, tol=1e-3) - - @jax.jit - def dcf( - signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray - ) -> jaxopt._src.base.OptStep: - """Run the quadratic programming using jaxopt OSQP. - - Args: - signs (jnp.ndarray): Sign combination - for the inequality constraints. - c (jnp.ndarray): Linear term in the objective function. - Q (jnp.ndarray): Quadratic term in the objective function. - - Returns: - sol: Solution of the quadratic programming problem. - """ - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) - h = jnp.zeros(Gmat.shape[0]) - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) # .params - return sol - - vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) - # Solve all QPs - sol = vmapped_dcf(all_signs, c, Q) - - if solver == "CvxpyQP": - qp = CvxpyQP() - - def dcf_cvxpyqp( - signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray - ) -> jaxopt._src.base.OptStep: - """Run the quadratic programming using Cvxpy. - - Args: - signs (jnp.ndarray): Sign combination for the - inequality constraints. - c (jnp.ndarray): Linear term in the objective function. - Q (jnp.ndarray): Quadratic term in the objective function. - - Returns: - sol: Solution of the quadratic programming problem. - """ - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) - h = jnp.zeros(Gmat.shape[0]) - - # Convert to numpy for cvxpy - Q_np = jnp.array(Q) - c_np = jnp.array(c) - Gmat_np = jnp.array(Gmat) - h_np = jnp.array(h) - - sol = qp.run( - init_params=jnp.ones(N), - params_obj=(Q_np, c_np), - params_ineq=(Gmat_np, h_np), - ) - return sol - - # Use a regular loop instead of vmap - solutions = [] - for i, signs in enumerate(all_signs): - sol = dcf_cvxpyqp(signs, c, Q) - solutions.append(sol) - sol = solutions.copy() + qp = OSQP(maxiter=10000, tol=1e-3) + + @jax.jit + def dcf( + signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray + ) -> jaxopt._src.base.OptStep: + """Run the quadratic programming using jaxopt OSQP. + + Args: + signs (jnp.ndarray): Sign combination + for the inequality constraints. + c (jnp.ndarray): Linear term in the objective function. + Q (jnp.ndarray): Quadratic term in the objective function. + + Returns: + sol: Solution of the quadratic programming problem. + """ + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + h = jnp.zeros(Gmat.shape[0]) + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) # .params + return sol + + vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) + # Solve all QPs + sol = vmapped_dcf(all_signs, c, Q) return { - "solver": solver, "state": sol.state, "params": sol.params.primal, "sol": sol, diff --git a/qptesting.py b/qptesting.py index c43026f..8f68b25 100644 --- a/qptesting.py +++ b/qptesting.py @@ -1,64 +1,87 @@ +"""Example use case for the qp solver.""" + +import time + +import jax +import matplotlib.pyplot as plt from jax import numpy as jnp -from maxsmooth.models import (normalised_polynomial, normalised_polynomial_basis) + from maxsmooth.derivatives import make_derivative_functions +from maxsmooth.models import normalised_polynomial, normalised_polynomial_basis from maxsmooth.qp import qp -import matplotlib.pyplot as plt -import jax - -jax.config.update('jax_enable_x64', True) +jax.config.update("jax_enable_x64", True) function = normalised_polynomial basis_function = normalised_polynomial_basis key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) -y = 5e6*x**(-2.5) + 0.01*jax.random.normal(key, x.shape) +y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) N = 8 -pivot_point = len(x)//2 +pivot_point = len(x) // 2 init_params = jnp.ones(N) -sol = qp(x, y, N, pivot_point, function, basis_function, solver='OSQP') +start = time.time() +qp = jax.jit( + qp, static_argnames=("N", "pivot_point", "function", "basis_function") +) +sol = qp(x, y, N, pivot_point, function, basis_function) +end = time.time() +print(f"QP solved in {end - start:.2f} seconds") objective_values = [] -for params in sol['params']: - - #plt.plot(x, y, 'o', label='data') - fit = jax.vmap(function, in_axes=(0, None, None, None)) \ - (x, x[pivot_point], y[pivot_point], params) - obj_val = jnp.sum((y - fit)**2) +for params in sol["params"]: + # plt.plot(x, y, 'o', label='data') + fit = jax.vmap(function, in_axes=(0, None, None, None))( + x, x[pivot_point], y[pivot_point], params + ) + obj_val = jnp.sum((y - fit) ** 2) objective_values.append(obj_val) -plt.plot(objective_values, 'o-') +plt.plot(objective_values, "o-") plt.xlabel("Solution index") plt.ylabel("Objective value") plt.title("Objective values for different constraint sign combinations") plt.show() minimum_index = jnp.argmin(jnp.array(objective_values)) -best_params = sol['params'][minimum_index] +best_params = sol["params"][minimum_index] print(best_params) -plt.plot(x, y, 'o', label='data') -best_fit = jax.vmap(function, in_axes=(0, None, None, None)) \ - (x, x[pivot_point], y[pivot_point], best_params) -plt.plot(x, best_fit, '-', label='best fit obj={:.2e}'.format(objective_values[minimum_index])) +plt.plot(x, y, "o", label="data") +best_fit = jax.vmap(function, in_axes=(0, None, None, None))( + x, x[pivot_point], y[pivot_point], best_params +) +plt.plot( + x, + best_fit, + "-", + label=f"best fit obj={objective_values[minimum_index]:.2e}", +) plt.legend() plt.show() -plt.plot(x, y - best_fit, 'o', label='residuals') -plt.axhline(0, color='k', ls='--') +plt.plot(x, y - best_fit, "o", label="residuals") +plt.axhline(0, color="k", ls="--") plt.legend() plt.show() deriv_funcs = make_derivative_functions(function, N) -derivs = [jax.vmap(df, in_axes=(0, None, None, None))(x, x[pivot_point], y[pivot_point], best_params) - for df in deriv_funcs] +derivs = [ + jax.vmap(df, in_axes=(0, None, None, None))( + x, x[pivot_point], y[pivot_point], best_params + ) + for df in deriv_funcs +] derivs = derivs[2:] # From 2nd derivative onwards -[plt.plot(x, derivs[m], label=f"{m+2}-th derivative") for m in range(len(derivs))] -plt.axhline(0, color='k', ls='--') +[ + plt.plot(x, derivs[m], label=f"{m + 2}-th derivative") + for m in range(len(derivs)) +] +plt.axhline(0, color="k", ls="--") plt.legend() -plt.show() \ No newline at end of file +plt.show() From 42730eb53158966b944505c62588927930e7ea16 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 3 Dec 2025 15:17:37 +0000 Subject: [PATCH 30/52] tinkering with the qp code --- maxsmooth/qp.py | 23 ++++++----------------- qptesting.py | 10 +++++----- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index 0ce0597..80d2183 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -33,7 +33,8 @@ def qp( dict: Dictionary containing solver information and solution. """ # needs some dummy parameters to make basis - basis = jax.vmap(basis_function, in_axes=(0, None, None, None))( + basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) + basis = basis_function( x, x[pivot_point], y[pivot_point], jnp.ones(N) ) Q = jnp.dot(basis.T, basis) @@ -41,23 +42,11 @@ def qp( c = -jnp.dot(basis.T, y) G = derivative_prefactors( function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N - ) - G = G[2:] - """G_scaled = [] - for i, g in enumerate(G): - # square root of sum of squares of each row - g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) - g_norm = jnp.where( - g_norm < 1e-10, 1.0, g_norm - ) # Avoid division by zero - G_scaled.append(g / g_norm) - G = G_scaled""" - - all_signs = list(product((-1.0, 1.0), repeat=len(G))) + )[2:] - all_signs = jnp.array(all_signs) + all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) - qp = OSQP(maxiter=10000, tol=1e-3) + qp = OSQP(maxiter=5000, tol=1e-3) @jax.jit def dcf( @@ -76,7 +65,7 @@ def dcf( """ Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) h = jnp.zeros(Gmat.shape[0]) - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) # .params + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) return sol vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) diff --git a/qptesting.py b/qptesting.py index 8f68b25..353cbbf 100644 --- a/qptesting.py +++ b/qptesting.py @@ -18,11 +18,9 @@ key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) -N = 8 +N = 15 pivot_point = len(x) // 2 -init_params = jnp.ones(N) - start = time.time() qp = jax.jit( qp, static_argnames=("N", "pivot_point", "function", "basis_function") @@ -31,10 +29,12 @@ end = time.time() print(f"QP solved in {end - start:.2f} seconds") +vmapped_function = jax.vmap(function, in_axes=(0, None, None, None)) + objective_values = [] for params in sol["params"]: # plt.plot(x, y, 'o', label='data') - fit = jax.vmap(function, in_axes=(0, None, None, None))( + fit = vmapped_function( x, x[pivot_point], y[pivot_point], params ) obj_val = jnp.sum((y - fit) ** 2) @@ -51,7 +51,7 @@ best_params = sol["params"][minimum_index] print(best_params) plt.plot(x, y, "o", label="data") -best_fit = jax.vmap(function, in_axes=(0, None, None, None))( +best_fit = vmapped_function( x, x[pivot_point], y[pivot_point], best_params ) plt.plot( From 2436047306b3e895a41d7de0e9e976c85d5ab3e0 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 3 Dec 2025 16:39:21 +0000 Subject: [PATCH 31/52] chaning outputs of qp and starting to think about the sign flipping algorihtm --- maxsmooth/qp.py | 77 +++++++++++++++++++++++++++++++++++++++++++------ qptesting.py | 11 ++----- 2 files changed, 71 insertions(+), 17 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index 80d2183..f4fac65 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -34,9 +34,7 @@ def qp( """ # needs some dummy parameters to make basis basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) - basis = basis_function( - x, x[pivot_point], y[pivot_point], jnp.ones(N) - ) + basis = basis_function(x, x[pivot_point], y[pivot_point], jnp.ones(N)) Q = jnp.dot(basis.T, basis) c = -jnp.dot(basis.T, y) @@ -73,11 +71,12 @@ def dcf( sol = vmapped_dcf(all_signs, c, Q) return { - "state": sol.state, + "status": sol.state.status, "params": sol.params.primal, - "sol": sol, + "error": sol.state.error, } + def fastqpsearch( x: jnp.ndarray, y: jnp.ndarray, @@ -85,7 +84,7 @@ def fastqpsearch( pivot_point: int, function: Callable, basis_function: Callable, - solver: str = "OSQP", + key: jnp.ndarray = jax.random.PRNGKey(0), ) -> dict: """Set up and solve the quadratic programming problem for maxsmooth. @@ -99,10 +98,70 @@ def fastqpsearch( pivot_point (int): Index of the pivot point. function (Callable): The model funciton from `maxsmooth.models`. basis_function (Callable): The basis function to use. - solver (str, optional): Solver to use ('OSQP' or 'CvxpyQP'). - Defaults to 'OSQP'. + key (jnp.ndarray): JAX random key. Returns: dict: Dictionary containing solver information and solution. """ - return NotImplementedError("fastqpsearch is not implemented yet.") \ No newline at end of file + + @jax.jit + def dcf( + signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray + ) -> jaxopt._src.base.OptStep: + """Run the quadratic programming using jaxopt OSQP. + + Args: + signs (jnp.ndarray): Sign combination + for the inequality constraints. + c (jnp.ndarray): Linear term in the objective function. + Q (jnp.ndarray): Quadratic term in the objective function. + + Returns: + sol: Solution of the quadratic programming problem. + """ + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + h = jnp.zeros(Gmat.shape[0]) + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) + return sol + + # needs some dummy parameters to make basis + basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) + basis = basis_function(x, x[pivot_point], y[pivot_point], jnp.ones(N)) + Q = jnp.dot(basis.T, basis) + + c = -jnp.dot(basis.T, y) + G = derivative_prefactors( + function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N + )[2:] + + all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) + + qp = OSQP(maxiter=5000, tol=1e-3) + + key, subkey = jax.random.split(key) + r = jax.random.choice(subkey, all_signs.shape[0], (1,)) + signs = all_signs[r[0]] + + sol = dcf(signs, c, Q) + error = sol.state.error + best_error = jnp.inf + + flip_sign = jax.vmap(lambda i, s: s.at[i].set(-s[i]), in_axes=(0, None)) + vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) + + while error < best_error: + best_error = error + flip_signs = flip_sign(jnp.arange(len(signs)), signs) + sol = vmapped_dcf(flip_signs, c, Q) + minimum_index = jnp.argmin(jnp.array([s.error for s in sol])) + test_signs = flip_signs[minimum_index] + new_error = sol[minimum_index].state.error + if new_error < error: + error = new_error + signs = test_signs + + return { + "state": sol.state, + "params": sol.params.primal, + "sol": sol, + } diff --git a/qptesting.py b/qptesting.py index 353cbbf..5cc9a51 100644 --- a/qptesting.py +++ b/qptesting.py @@ -18,7 +18,7 @@ key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) -N = 15 +N = 8 pivot_point = len(x) // 2 start = time.time() @@ -34,9 +34,7 @@ objective_values = [] for params in sol["params"]: # plt.plot(x, y, 'o', label='data') - fit = vmapped_function( - x, x[pivot_point], y[pivot_point], params - ) + fit = vmapped_function(x, x[pivot_point], y[pivot_point], params) obj_val = jnp.sum((y - fit) ** 2) objective_values.append(obj_val) @@ -49,11 +47,8 @@ minimum_index = jnp.argmin(jnp.array(objective_values)) best_params = sol["params"][minimum_index] -print(best_params) plt.plot(x, y, "o", label="data") -best_fit = vmapped_function( - x, x[pivot_point], y[pivot_point], best_params -) +best_fit = vmapped_function(x, x[pivot_point], y[pivot_point], best_params) plt.plot( x, best_fit, From 26bc33824bb0e8198a913e6e305d604366a58599 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 3 Dec 2025 17:09:06 +0000 Subject: [PATCH 32/52] some form of sign flipping but not same as in the paper --- maxsmooth/qp.py | 26 +++++++++++++++++--------- qptesting.py | 17 +++++++++++++++-- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index f4fac65..7ede9a8 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -149,19 +149,27 @@ def dcf( flip_sign = jax.vmap(lambda i, s: s.at[i].set(-s[i]), in_axes=(0, None)) vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) - while error < best_error: + initial_state = (error, best_error, signs, c, Q, sol.params.primal) + + def condition(state: tuple) -> bool: + error, best_error, _, _, _, _ = state + return error < best_error + + def body(state: tuple) -> tuple: + error, best_error, signs, c, Q, best_params = state best_error = error flip_signs = flip_sign(jnp.arange(len(signs)), signs) sol = vmapped_dcf(flip_signs, c, Q) - minimum_index = jnp.argmin(jnp.array([s.error for s in sol])) + minimum_index = jnp.argmin(jnp.array(sol.state.error)) test_signs = flip_signs[minimum_index] - new_error = sol[minimum_index].state.error - if new_error < error: - error = new_error - signs = test_signs + new_error = sol.state.error[minimum_index] + best_params = sol.params.primal[minimum_index] + return (new_error, best_error, test_signs, c, Q, best_params) + + results = jax.lax.while_loop(condition, body, initial_state) return { - "state": sol.state, - "params": sol.params.primal, - "sol": sol, + "state": jnp.array([]), + "params": results[5], + "sol": jnp.array([]), } diff --git a/qptesting.py b/qptesting.py index 5cc9a51..b0534b6 100644 --- a/qptesting.py +++ b/qptesting.py @@ -8,7 +8,7 @@ from maxsmooth.derivatives import make_derivative_functions from maxsmooth.models import normalised_polynomial, normalised_polynomial_basis -from maxsmooth.qp import qp +from maxsmooth.qp import fastqpsearch, qp jax.config.update("jax_enable_x64", True) @@ -18,9 +18,22 @@ key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) -N = 8 +N = 15 pivot_point = len(x) // 2 +fastqpsearch = jax.jit( + fastqpsearch, + static_argnames=("N", "pivot_point", "function", "basis_function"), +) +start = time.time() +fastqpsearch_sol = fastqpsearch( + x, y, N, pivot_point, function, basis_function, key=key +) +end = time.time() +print(f"Fast QP search solved in {end - start:.2f} seconds") +print(fastqpsearch_sol) +exit() + start = time.time() qp = jax.jit( qp, static_argnames=("N", "pivot_point", "function", "basis_function") From 55328e98c2eec9d6b3a390eeabbd34b850db4458 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 3 Dec 2025 18:09:52 +0000 Subject: [PATCH 33/52] the sign flipping algorithm in the paper isnt going to help because all the cost is in compilation --- maxsmooth/DCF.py | 843 ----------------------------------------------- maxsmooth/qp.py | 98 ------ 2 files changed, 941 deletions(-) delete mode 100755 maxsmooth/DCF.py diff --git a/maxsmooth/DCF.py b/maxsmooth/DCF.py deleted file mode 100755 index c38a1d4..0000000 --- a/maxsmooth/DCF.py +++ /dev/null @@ -1,843 +0,0 @@ - -""" -*smooth*, as demonstrated in the examples section, -is used to call the fitting routine. There are a number -of :math:`{^{**}}` kwargs that can be assigned to the function which change how -the fit is performed, the model that is fit and various other attributes. -These are detailed below. - -""" - -from maxsmooth.qp import qp_class -from maxsmooth.Models import Models_class -from maxsmooth.derivatives import derivative_class -from maxsmooth.Data_save import save, save_optimum -from itertools import product -import warnings -import numpy as np -import time -import os -import shutil - - -class smooth(object): - - r""" - - **Parameters:** - - x: **numpy.array** - | The x data points for the set being fitted. - - y: **numpy.array** - | The y data points for fitting. - - N: **int** - | The number of terms in the DCF. - - **Kwargs:** - - fit_type: **Default = 'qp-sign_flipping'** - | This kwarg allows the user to - switch between sampling the available discrete sign spaces - (default) or testing all sign combinations on the derivatives - which can be accessed by setting to 'qp'. - - model_type: **Default = 'difference_polynomial'** - | Allows the user to - access default Derivative Constrained Functions built into the - software. Available options include the default, 'polynomial', - 'normalised_polynomial', 'legendre', 'log_polynomial', - 'loglog_polynomial' and 'exponential'. For more details on the - functional form of the built in basis see the ``maxsmooth`` - paper. - - **pivot_point: Default = len(x)//2 otherwise an integer between** - **-len(x) and len(x)** - | Some of the built in - models rely on pivot points in the data sets which by defualt - is set as the middle index. This can be altered via - this kwarg which can occasionally lead to a better quality fit. - - base_dir: **Default = 'Fitted_Output/'** - | The location of the outputted - data from ``maxsmooth``. This must be a string and end in '/'. - If the file does not exist then ``maxsmooth`` will create it. - By default the only outputted data is a summary of the best - fit but additional data can be recorded by setting the keyword - argument 'data_save = True'. - - data_save: **Default = False** - | By setting this to True the algorithm - will save every tested set of parameters, signs and objective - function evaluations into files in base_dir. Theses files will - be over written on repeated runs but they are needed to run the - 'chidist_plotter'. - - print_output: **Default = 1** - | The parameter can take a value of 0, 1, 2. - If set to 2 this outputs to the - terminal every fit performed by the algorithm. By default the - parameter has a value of 1 and the - only output is the optimal solution once the code is finished. - Setting this to 0 will prevent any output to the terminal. This - is useful when running the code inside a nested sampling loop - for example. - - cvxopt_maxiter: **Default = 10000 else integer** - | This shouldn't need - changing for most problems however if ``CVXOPT`` fails with a - 'maxiters reached' error message this can be increased. - Doing so arbitrarily will however increase the run time of - ``maxsmooth``. - - initial_params: **Default = None else list of length N** - | Allows the user - to overwrite the default initial parameters used by ``CVXOPT``. - - **constraints: Default = 2 else an integer less than or equal** - **to N - 1** - | The minimum constrained derivative order which is set by default - to 2 for a Maximally Smooth Function. - - zero_crossings: **Default = None else list of integers** - | Allows you to - specify if the conditions should be relaxed on any - of the derivatives between constraints and the highest order - derivative. e.g. a 6th order fit with just a constrained 2nd - and 3rd order derivative would have zero_crossings = [4, 5]. - - cap: **Default = (len(available_signs)//N) + N else an integer** - | Determines the maximum number of signs explored either side of - the minimum :math:`{\chi^2}` value found after the decent - algorithm has terminated. - - chi_squared_limit: **Default = 2 else float or int** - | The prefactor on the maximum allowed increase in :math:`{\chi^2}` - during the directional exploration which is defaulted at 2. - If this value multiplied by the minimum :math:`{\chi^2}` - value found after the descent algorithm is exceeded then the - exploration in one direction is stopped and started in the - other. For more details on this and 'cap' see the ``maxsmooth`` - paper. - - The following Kwargs can be used by the user to define their own basis - function and will overwrite the 'model_type' kwarg. - - **basis_function: Default = None else function with parameters** - **(x, y, pivot_point, N)** - | This is a function of basis functions - for the quadratic programming. The variable pivot_point is the - index at the middle of the datasets x and y by default but can - be adjusted. - - **model: Default = None else function with parameters** - **(x, y, pivot_point, N, params)** - | This is - a user defined function describing the model to be fitted to - the data. - - **der_pres: Default = None else function with parameters** - **(m, x, y, N, pivot_point)** - | This function describes the prefactors on the - mth order derivative used in defining the constraint. - - **derivatives: Default = None else function with parameters** - **(m, x, y, N, pivot_point, params)** - | User defined function describing the mth - order derivative used to check that conditions are being met. - - **args: Default = None else list** - | Extra arguments for `smooth` - to pass to the functions detailed above. - - **Output** - - .y_fit: **numpy.array** - | The fitted array of y data from smooth(). - - .optimum_chi: **float** - | The optimum :math:`{\chi^2}` value for the fit calculated by, - - .. math:: - - {X^2=\sum(y-y_{fit})^2}. - - .optimum_params: **numpy.array** - | The set of parameters corresponding to the optimum fit. - - .rms: **float** - | The rms value of the residuals :math:`{y_{res}=y-y_{fit}}` - calculated by, - - .. math:: - - {rms=\sqrt{\frac{\sum(y-y_{fit})^2}{n}}} - - where :math:`n` is the number of data points. - - .derivatives: **numpy.array** - | The :math:`m^{th}` order derivatives. - - .optimum_signs: **numpy.array** - | The sign combinations corresponding to the - optimal result. The nature of the constraint means that a - negative ``maxsmooth`` sign implies a positive :math:`{m^{th}}` - order derivative and visa versa. - - """ - - def __init__(self, x, y, N, **kwargs): - self.x = x - self.y = y - - self.N = N - if self.N % 1 != 0: - raise ValueError('N must be an integer or whole number float.') - - for keys, values in kwargs.items(): - if keys not in set( - ['fit_type', 'model_type', 'base_dir', - 'print_output', 'cvxopt_maxiter', 'zero_crossings', - 'data_save', - 'constraints', 'chi_squared_limit', 'cap', - 'initial_params', 'basis_functions', - 'der_pres', 'model', - 'derivatives', 'args', 'pivot_point']): - raise KeyError("Unexpected keyword argument in smooth().") - - self.fit_type = kwargs.pop('fit_type', 'qp-sign_flipping') - if self.fit_type not in set(['qp', 'qp-sign_flipping']): - raise KeyError( - "Invalid 'fit_type'. Valid entries include 'qp'\n" + - "'qp-sign_flipping'") - - self.pivot_point = kwargs.pop('pivot_point', len(self.x)//2) - if type(self.pivot_point) is not int: - raise TypeError('Pivot point is not an integer index.') - elif self.pivot_point >= len(self.x) or \ - self.pivot_point < -len(self.x): - raise ValueError( - 'Pivot point must be in the range -len(x) - len(x).') - - self.base_dir = kwargs.pop('base_dir', 'Fitted_Output/') - if type(self.base_dir) is not str: - raise KeyError("'base_dir' must be a string ending in '/'.") - elif self.base_dir.endswith('/') is False: - raise KeyError("'base_dir' must end in '/'.") - - self.model_type = kwargs.pop('model_type', 'difference_polynomial') - if self.model_type not in set( - ['normalised_polynomial', 'polynomial', - 'log_polynomial', 'loglog_polynomial', - 'difference_polynomial', - 'exponential', 'legendre']): - raise KeyError( - "Invalid 'model_type'. See documentation for built" + - "in models.") - - self.cvxopt_maxiter = kwargs.pop('cvxopt_maxiter', 10000) - if type(self.cvxopt_maxiter) is not int: - raise ValueError("'cvxopt_maxiter' is not integer.") - - self.print_output = kwargs.pop('print_output', 1) - if self.print_output not in [0, 1, 2]: - raise ValueError("'print_output' must have a value in the set" + - " [0, 1, 2]. See documentation for details.") - - self.data_save = kwargs.pop('data_save', False) - if type(self.data_save) is not bool: - raise TypeError( - "Boolean keyword argument with value 'data_save'" + - " is not True or False.") - - self.constraints = kwargs.pop('constraints', 2) - if type(self.constraints) is not int: - raise TypeError("'constraints' is not an integer") - if self.constraints > self.N-1: - raise ValueError( - "'constraints' exceeds the number of derivatives.") - - self.zero_crossings = kwargs.pop('zero_crossings', None) - if self.zero_crossings is not None: - for i in range(len(self.zero_crossings)): - if type(self.zero_crossings[i]) is not int: - raise TypeError( - "Entries in 'zero_crossings'" + - " are not integer.") - if self.zero_crossings[i] < self.constraints: - raise ValueError( - 'One or more specified derivatives for' + - ' zero crossings is less than the minimum' + - ' constrained' + - ' derivative.\n zero_crossings = ' + - str(self.zero_crossings) - + '\n' + ' Minimum Constrained Derivative = ' - + str(self.constraints)) - - self.chi_squared_limit = kwargs.pop('chi_squared_limit', None) - self.cap = kwargs.pop('cap', None) - if self.chi_squared_limit is not None: - if isinstance(self.chi_squared_limit, int) or \ - isinstance(self.chi_squared_limit, float): - pass - else: - raise TypeError( - "Limit on maximum allowed increase in chi squared" + - ", 'chi_squared_limit', is not an integer or float.") - if self.cap is not None: - if type(self.cap) is not int: - raise TypeError( - "The cap on directional exploration" + - ", 'cap', is not an integer.") - - self.initial_params = kwargs.pop('initial_params', None) - if self.initial_params is not None and len(self.initial_params) \ - != self.N: - raise ValueError( - "Initial Parameters is not equal to the number" + - "of terms in the polynomial, N.") - if self.initial_params is not None and len(self.initial_params) \ - == self.N: - for i in range(len(self.initial_params)): - if type(self.initial_params[i]) is not int: - if type(self.initial_params[i]) is not float: - raise ValueError( - 'One or more initial' + - 'parameters is not numeric.') - - self.basis_functions = kwargs.pop('basis_functions', None) - self.der_pres = kwargs.pop('der_pres', None) - self.model = kwargs.pop('model', None) - self.derivatives_function = kwargs.pop('derivatives', None) - self.args = kwargs.pop('args', None) - - self.new_basis = { - 'basis_function': - self.basis_functions, 'der_pres': self.der_pres, - 'derivatives_function': self.derivatives_function, - 'model': self.model, 'args': self.args} - if np.all([value is None for value in self.new_basis.values()]): - pass - else: - count = 0 - for key, value in self.new_basis.items(): - if value is None and key != 'args': - raise KeyError( - 'Attempt to change basis functions failed.' + - ' One or more functions not defined.' + - ' Please consult documentation.') - if value is None and key == 'args': - warnings.warn( - 'Warning: No additional arguments passed to' + - ' new basis functions') - count += 1 - if count == len(self.new_basis): - self.model_type = 'user_defined' - - self.y_fit, self.optimum_signs, self.optimum_params, \ - self.derivatives,\ - self.optimum_chi, self.rms, self.optimum_zc_dict \ - = self.fitting() - - def fitting(self): - - def signs_array(nums): - return np.array(list(product(*((x, -x) for x in nums)))) - - if not os.path.exists(self.base_dir): - os.mkdir(self.base_dir) - - if os.path.isdir(self.base_dir+'Output_Parameters/'): - shutil.rmtree(self.base_dir+'Output_Parameters/') - if os.path.isdir(self.base_dir+'Output_Signs/'): - shutil.rmtree(self.base_dir+'Output_Signs/') - if os.path.isdir(self.base_dir+'Output_Evaluation/'): - shutil.rmtree(self.base_dir+'Output_Evaluation/') - - def qp(x, y, pivot_point): # Testing all signs - - start = time.time() - - if self.zero_crossings is not None: - signs = signs_array([1]*( - self.N-self.constraints-len(self.zero_crossings))) - else: - signs = signs_array([1]*(self.N-self.constraints)) - - params, chi_squared, zc_dict, passed_signs = [], [], [], [] - append_params, append_chi, append_zc_dict, append_passed_signs = \ - params.append, chi_squared.append, zc_dict.append, \ - passed_signs.append - for j in range(signs.shape[0]): - fit = qp_class( - x, y, self.N, signs[j, :], pivot_point, - self.model_type, self.cvxopt_maxiter, - self.zero_crossings, - self.initial_params, self.constraints, self.new_basis) - - if self.print_output == 2: - print('-'*50) - print('Polynomial Order:', self.N) - if self.zero_crossings is not None: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints-len(self.zero_crossings)) - else: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints) - print('Signs :', signs[j, :]) - print('Objective Function Value:', fit.chi_squared) - print('Parameters:', (fit.parameters).T) - print('Method:', self.fit_type) - print('Model:', self.model_type) - print('Constraints: m >=', self.constraints) - if self.zero_crossings is None: - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative order "i"):', - fit.zc_dict) - if self.zero_crossings is not None: - print( - 'Zero Crossing Derivatives:', self.zero_crossings) - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative order "i"):', - fit.zc_dict) - print('-'*50) - - append_params(fit.parameters) - append_chi(fit.chi_squared) - append_zc_dict(fit.zc_dict) - append_passed_signs(signs[j, :]) - if self.data_save is True: - save( - self.base_dir, fit.parameters, fit.chi_squared, - signs[j, :], self.N, self.fit_type) - - params, chi_squared, zc_dict, passed_signs = np.array(params), \ - np.array(chi_squared), np.array(zc_dict), \ - np.array(passed_signs) - - Optimum_chi_squared = chi_squared.min() - for f in range(len(chi_squared)): - if chi_squared[f] == chi_squared.min(): - Optimum_params = params[f, :] - Optimum_sign_combination = passed_signs[f, :] - - y_fit = Models_class( - Optimum_params, x, y, self.N, pivot_point, - self.model_type, self.new_basis).y_sum - der = derivative_class( - x, y, Optimum_params, self.N, - pivot_point, self.model_type, self.zero_crossings, - self.constraints, self.new_basis) - derivatives, Optimum_zc_dict = der.derivatives, der.zc_dict - - end = time.time() - - if self.print_output in [1, 2]: - print('#'*50) - print('-'*20 + 'OPTIMUM RESULT' + '-'*20) - print('Time:', end-start) - print('Polynomial Order:', self.N) - if self.zero_crossings is not None: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints-len(self.zero_crossings)) - else: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints) - print('Signs :', Optimum_sign_combination) - print('Objective Function Value:', Optimum_chi_squared) - print('Parameters:', Optimum_params.T) - print('Method:', self.fit_type) - print('Model:', self.model_type) - print('Constraints: m >=', self.constraints) - if self.zero_crossings is None: - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative order "i"):', - Optimum_zc_dict) - if self.zero_crossings is not None: - print('Zero Crossing Derivatives:', self.zero_crossings) - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative order "i"):', - Optimum_zc_dict) - print('-'*50) - print('#'*50) - - save_optimum( - self.base_dir, end-start, self.N, - Optimum_sign_combination, Optimum_chi_squared, - Optimum_params, self.fit_type, self.model_type, - self.zero_crossings, Optimum_zc_dict, self.constraints) - - return y_fit, derivatives, Optimum_chi_squared, Optimum_params, \ - Optimum_sign_combination, Optimum_zc_dict - - def qp_sign_flipping(x, y, pivot_point): # Sign Sampling - - start = time.time() - - if self.zero_crossings is not None: - array_signs = signs_array([1]*( - self.N-self.constraints-len(self.zero_crossings))) - else: - array_signs = signs_array([1]*(self.N-self.constraints)) - - r = np.random.randint(0, len(array_signs), 1) - signs = array_signs[r][0] - - tested_indices = [] - chi_squared = [] - parameters = [] - tested_signs = [] - for i in range(len(array_signs)): - if i == r: - tested_indices.append(i) - fit = qp_class( - x, y, self.N, signs, pivot_point, - self.model_type, self.cvxopt_maxiter, - self.zero_crossings, - self.initial_params, self.constraints, self.new_basis) - chi_squared.append(fit.chi_squared) - tested_signs.append(signs) - parameters.append(fit.parameters) - chi_squared_old = fit.chi_squared - previous_signs = signs - - if self.print_output == 2: - print('-'*50) - print('Polynomial Order:', self.N) - if self.zero_crossings is not None: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints-len(self.zero_crossings)) - else: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints) - print('Signs :', signs) - print('Objective Function Value:', chi_squared_old) - print('Parameters:', (fit.parameters).T) - print('Method:', self.fit_type) - print('Model:', self.model_type) - print('Constraints: m >=', self.constraints) - if self.zero_crossings is None: - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative order "i"):', - fit.zc_dict) - if self.zero_crossings is not None: - print( - 'Zero Crossing Derivatives:', - self.zero_crossings) - print( - 'Zero Crossings Used? (0 signifies' + - 'Yes\n in derivative order "i"):', fit.zc_dict) - print('-'*50) - if self.data_save is True: - save( - self.base_dir, fit.parameters, fit.chi_squared, - signs, self.N, self.fit_type) - - # Transforms or 'steps' of sign combination - sign_transform = [] - for i in range(len(signs)): - base = np.array([1]*len(signs)) - base[i] = -1 - sign_transform.append(base) - sign_transform = np.array(sign_transform) - chi_squared_new = 0 - - while chi_squared_new < chi_squared_old: - if chi_squared_new != 0: - chi_squared_old = chi_squared_new - for h in range(sign_transform.shape[0]): - signs = previous_signs * sign_transform[h] - for i in range(len(array_signs)): - if np.all(signs == array_signs[i]): - ind = i - if ind in set(tested_indices): - pass - else: - tested_indices.append(ind) - fit = qp_class( - x, y, self.N, signs, pivot_point, - self.model_type, self.cvxopt_maxiter, - self.zero_crossings, self.initial_params, - self.constraints, self.new_basis) - if fit.chi_squared < chi_squared_old: - chi_squared_new = fit.chi_squared - previous_signs = signs - chi_squared.append(fit.chi_squared) - tested_signs.append(signs) - parameters.append(fit.parameters) - - if self.print_output == 2: - print('-'*50) - print('Polynomial Order:', self.N) - if self.zero_crossings is not None: - print( - 'Number of Constrained Derivatives:', - self.N - self.constraints - - len(self.zero_crossings)) - else: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints) - print('Signs :', signs) - print( - 'Objective Function Value:', - fit.chi_squared) - print('Parameters:', fit.parameters.T) - print('Method:', self.fit_type) - print('Model:', self.model_type) - print('Constraints: m >=', self.constraints) - if self.zero_crossings is None: - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative' + - ' order "i"):', - fit.zc_dict) - if self.zero_crossings is not None: - print( - 'Zero Crossing Derivatives:', - self.zero_crossings) - print( - 'Zero Crossings Used?' + - ' (0 signifies' + - 'Yes\n in derivative order "i"):', - fit.zc_dict) - print('-'*50) - if self.data_save is True: - save( - self.base_dir, fit.parameters, - fit.chi_squared, - signs, self.N, self.fit_type) - - break - if h == sign_transform.shape[0] - 1: - chi_squared_new = chi_squared_old - break - - if self.data_save is True: - np.save( - self.base_dir + str(self.N) + - '_'+self.fit_type+'_minimum_chi_post_descent.npy', - min(chi_squared)) - - if self.chi_squared_limit is not None: - lim = self.chi_squared_limit*min(chi_squared) - else: - lim = 2*min(chi_squared) - - if self.cap is not None: - cap = self.cap - else: - cap = (len(array_signs)//self.N) + self.N - - for i in range(len(array_signs)): - if np.all(previous_signs == array_signs[i]): - index = i - - down_int = 1 - while down_int < cap: - if index-down_int < 0: - break - elif (index-down_int) in set(tested_indices): - chi_down = 0 - pass - else: - signs = array_signs[index-down_int] - tested_indices.append(index - down_int) - fit = qp_class( - x, y, self.N, signs, pivot_point, - self.model_type, self.cvxopt_maxiter, - self.zero_crossings, self.initial_params, - self.constraints, self.new_basis) - chi_down = fit.chi_squared - chi_squared.append(fit.chi_squared) - tested_signs.append(signs) - parameters.append(fit.parameters) - - if self.print_output == 2: - print('-'*50) - print('Polynomial Order:', self.N) - if self.zero_crossings is not None: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints - - len(self.zero_crossings)) - else: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints) - print('Signs :', signs) - print('Objective Function Value:', fit.chi_squared) - print('Parameters:', fit.parameters.T) - print('Method:', self.fit_type) - print('Model:', self.model_type) - print('Constraints: m >=', self.constraints) - if self.zero_crossings is None: - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative' + - ' order "i"):', - fit.zc_dict) - if self.zero_crossings is not None: - print( - 'Zero Crossing Derivatives:', - self.zero_crossings) - print( - 'Zero Crossings Used? (0 signifies' + - 'Yes\n in derivative order "i"):', - fit.zc_dict) - print('-'*50) - if self.data_save is True: - save( - self.base_dir, fit.parameters, fit.chi_squared, - signs, self.N, self.fit_type) - - if chi_down > lim: - break - down_int += 1 - - up_int = 1 - while up_int < cap: - if index+up_int >= len(array_signs): - break - elif (index + up_int) in set(tested_indices): - chi_up = 0 - pass - else: - signs = array_signs[index+up_int] - tested_indices.append(index + up_int) - fit = qp_class( - x, y, self.N, signs, pivot_point, - self.model_type, self.cvxopt_maxiter, - self.zero_crossings, self.initial_params, - self.constraints, self.new_basis) - chi_up = fit.chi_squared - chi_squared.append(fit.chi_squared) - tested_signs.append(signs) - parameters.append(fit.parameters) - - if self.print_output == 2: - print('-'*50) - print('Polynomial Order:', self.N) - if self.zero_crossings is not None: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints - - len(self.zero_crossings)) - else: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints) - print('Signs :', signs) - print('Objective Function Value:', fit.chi_squared) - print('Parameters:', fit.parameters.T) - print('Method:', self.fit_type) - print('Model:', self.model_type) - print('Constraints: m >=', self.constraints) - if self.zero_crossings is None: - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative' + - ' order "i"):', - fit.zc_dict) - if self.zero_crossings is not None: - print( - 'Zero Crossing Derivatives:', - self.zero_crossings) - print( - 'Zero Crossings Used? (0 signifies' + - 'Yes\n in derivative order "i"):', - fit.zc_dict) - print('-'*50) - if self.data_save is True: - save( - self.base_dir, fit.parameters, fit.chi_squared, - signs, self.N, self.fit_type) - - if chi_up > lim: - break - up_int += 1 - - for i in range(len(chi_squared)): - if chi_squared[i] == min(chi_squared): - Optimum_params = parameters[i] - Optimum_sign_combination = tested_signs[i] - Optimum_chi_squared = chi_squared[i] - - y_fit = Models_class( - Optimum_params, x, y, self.N, pivot_point, - self.model_type, self.new_basis).y_sum - der = derivative_class( - x, y, Optimum_params, self.N, - pivot_point, self.model_type, self.zero_crossings, - self.constraints, self.new_basis) - derivatives, Optimum_zc_dict = der.derivatives, der.zc_dict - - end = time.time() - - if self.print_output in [1, 2]: - print('#'*50) - print('-'*20 + 'OPTIMUM RESULT' + '-'*20) - print('Time:', end-start) - print('Polynomial Order:', self.N) - if self.zero_crossings is not None: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints-len(self.zero_crossings)) - else: - print( - 'Number of Constrained Derivatives:', - self.N-self.constraints) - print('Signs :', Optimum_sign_combination) - print('Objective Function Value:', Optimum_chi_squared) - print('Parameters:', Optimum_params.T) - print('Method:', self.fit_type) - print('Model:', self.model_type) - print('Constraints: m >=', self.constraints) - if self.zero_crossings is None: - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative order "i"):', - Optimum_zc_dict) - if self.zero_crossings is not None: - print('Zero Crossing Derivatives:', self.zero_crossings) - print( - 'Zero Crossings Used?' + - ' (0 signifies Yes\n in derivative order "i"):', - Optimum_zc_dict) - print('-'*50) - print('#'*50) - - save_optimum( - self.base_dir, end-start, self.N, - Optimum_sign_combination, Optimum_chi_squared, - Optimum_params, self.fit_type, self.model_type, - self.zero_crossings, Optimum_zc_dict, self.constraints) - - return y_fit, derivatives, Optimum_chi_squared, Optimum_params, \ - Optimum_sign_combination, Optimum_zc_dict - - if self.fit_type == 'qp': - y_fit, derivatives, Optimum_chi_squared, Optimum_params, \ - Optimum_sign_combination, Optimum_zc_dict = \ - qp(self.x, self.y, self.pivot_point) - if self.fit_type == 'qp-sign_flipping': - y_fit, derivatives, Optimum_chi_squared, Optimum_params, \ - Optimum_sign_combination, Optimum_zc_dict = \ - qp_sign_flipping(self.x, self.y, self.pivot_point) - - rms = (np.sqrt(np.sum((self.y-y_fit)**2)/len(self.y))) - - return y_fit, Optimum_sign_combination, Optimum_params, derivatives, \ - Optimum_chi_squared, rms, Optimum_zc_dict diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index 7ede9a8..d1bce4e 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -75,101 +75,3 @@ def dcf( "params": sol.params.primal, "error": sol.state.error, } - - -def fastqpsearch( - x: jnp.ndarray, - y: jnp.ndarray, - N: int, - pivot_point: int, - function: Callable, - basis_function: Callable, - key: jnp.ndarray = jax.random.PRNGKey(0), -) -> dict: - """Set up and solve the quadratic programming problem for maxsmooth. - - fastqpsearch uses the searching algorithm detailed in the maxsmooth - paper to reduce the number of QP solves needed. - - Args: - x (jnp.ndarray): Input data points. - y (jnp.ndarray): Output data points. - N (int): Number of basis functions. - pivot_point (int): Index of the pivot point. - function (Callable): The model funciton from `maxsmooth.models`. - basis_function (Callable): The basis function to use. - key (jnp.ndarray): JAX random key. - - Returns: - dict: Dictionary containing solver information and solution. - """ - - @jax.jit - def dcf( - signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray - ) -> jaxopt._src.base.OptStep: - """Run the quadratic programming using jaxopt OSQP. - - Args: - signs (jnp.ndarray): Sign combination - for the inequality constraints. - c (jnp.ndarray): Linear term in the objective function. - Q (jnp.ndarray): Quadratic term in the objective function. - - Returns: - sol: Solution of the quadratic programming problem. - """ - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) - h = jnp.zeros(Gmat.shape[0]) - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) - return sol - - # needs some dummy parameters to make basis - basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) - basis = basis_function(x, x[pivot_point], y[pivot_point], jnp.ones(N)) - Q = jnp.dot(basis.T, basis) - - c = -jnp.dot(basis.T, y) - G = derivative_prefactors( - function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N - )[2:] - - all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) - - qp = OSQP(maxiter=5000, tol=1e-3) - - key, subkey = jax.random.split(key) - r = jax.random.choice(subkey, all_signs.shape[0], (1,)) - signs = all_signs[r[0]] - - sol = dcf(signs, c, Q) - error = sol.state.error - best_error = jnp.inf - - flip_sign = jax.vmap(lambda i, s: s.at[i].set(-s[i]), in_axes=(0, None)) - vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) - - initial_state = (error, best_error, signs, c, Q, sol.params.primal) - - def condition(state: tuple) -> bool: - error, best_error, _, _, _, _ = state - return error < best_error - - def body(state: tuple) -> tuple: - error, best_error, signs, c, Q, best_params = state - best_error = error - flip_signs = flip_sign(jnp.arange(len(signs)), signs) - sol = vmapped_dcf(flip_signs, c, Q) - minimum_index = jnp.argmin(jnp.array(sol.state.error)) - test_signs = flip_signs[minimum_index] - new_error = sol.state.error[minimum_index] - best_params = sol.params.primal[minimum_index] - return (new_error, best_error, test_signs, c, Q, best_params) - - results = jax.lax.while_loop(condition, body, initial_state) - - return { - "state": jnp.array([]), - "params": results[5], - "sol": jnp.array([]), - } From f8f63ac9c2b7e5dac6b0687bd0da8755304e4efc Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 3 Dec 2025 18:19:05 +0000 Subject: [PATCH 34/52] some formatting --- qptesting.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/qptesting.py b/qptesting.py index b0534b6..7b52851 100644 --- a/qptesting.py +++ b/qptesting.py @@ -4,11 +4,12 @@ import jax import matplotlib.pyplot as plt +import tqdm from jax import numpy as jnp from maxsmooth.derivatives import make_derivative_functions from maxsmooth.models import normalised_polynomial, normalised_polynomial_basis -from maxsmooth.qp import fastqpsearch, qp +from maxsmooth.qp import qp jax.config.update("jax_enable_x64", True) @@ -18,34 +19,27 @@ key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) -N = 15 +N = 10 pivot_point = len(x) // 2 -fastqpsearch = jax.jit( - fastqpsearch, - static_argnames=("N", "pivot_point", "function", "basis_function"), +qp = jax.jit( + qp, static_argnames=("N", "pivot_point", "function", "basis_function") ) start = time.time() -fastqpsearch_sol = fastqpsearch( - x, y, N, pivot_point, function, basis_function, key=key -) +sol = qp(x, y, N, pivot_point, function, basis_function) end = time.time() -print(f"Fast QP search solved in {end - start:.2f} seconds") -print(fastqpsearch_sol) -exit() +print(f"First Call: QP solved in {end - start:.5f} seconds") start = time.time() -qp = jax.jit( - qp, static_argnames=("N", "pivot_point", "function", "basis_function") -) sol = qp(x, y, N, pivot_point, function, basis_function) end = time.time() -print(f"QP solved in {end - start:.2f} seconds") +print(f"Second Call: QP solved in {end - start:.5f} seconds") vmapped_function = jax.vmap(function, in_axes=(0, None, None, None)) objective_values = [] -for params in sol["params"]: +for i in tqdm.tqdm(range(len(sol["params"]))): + params = sol["params"][i] # plt.plot(x, y, 'o', label='data') fit = vmapped_function(x, x[pivot_point], y[pivot_point], params) obj_val = jnp.sum((y - fit) ** 2) From 98f2ed1e5f398c171bf03e1030013528febcc6a9 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 3 Dec 2025 20:34:34 +0000 Subject: [PATCH 35/52] some issue accessing the output of the function --- maxsmooth/qp.py | 19 ++++++++++++++----- qptesting.py | 43 ++++++++++++++----------------------------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index d1bce4e..a1e4555 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -70,8 +70,17 @@ def dcf( # Solve all QPs sol = vmapped_dcf(all_signs, c, Q) - return { - "status": sol.state.status, - "params": sol.params.primal, - "error": sol.state.error, - } + vmapped_function = jax.vmap(function, in_axes=(0, None, None, None)) + + objective_values = [] + for i in range(len(sol)): + fit = vmapped_function(x, x[pivot_point], y[pivot_point], + sol.params.primal[i]) + obj_val = jnp.sum((y - fit) ** 2) + objective_values.append(obj_val) + best_index = jnp.argmin(jnp.array(objective_values)) + + params = sol.params.primal[best_index] + print(params) + + return sol.state.status[best_index], sol.params.primal[best_index], sol.state.error[best_index] diff --git a/qptesting.py b/qptesting.py index 7b52851..b83b581 100644 --- a/qptesting.py +++ b/qptesting.py @@ -6,8 +6,8 @@ import matplotlib.pyplot as plt import tqdm from jax import numpy as jnp +from itertools import product -from maxsmooth.derivatives import make_derivative_functions from maxsmooth.models import normalised_polynomial, normalised_polynomial_basis from maxsmooth.qp import qp @@ -22,26 +22,29 @@ N = 10 pivot_point = len(x) // 2 -qp = jax.jit( +qp_jitted = jax.jit( qp, static_argnames=("N", "pivot_point", "function", "basis_function") ) start = time.time() -sol = qp(x, y, N, pivot_point, function, basis_function) +status, params, error = qp_jitted(x, y, N, pivot_point, function, basis_function) end = time.time() print(f"First Call: QP solved in {end - start:.5f} seconds") - +print(params) +exit() start = time.time() -sol = qp(x, y, N, pivot_point, function, basis_function) +status, params, error = qp_jitted(x, y, N, pivot_point, function, basis_function) end = time.time() print(f"Second Call: QP solved in {end - start:.5f} seconds") - +print(status) +print(params) +exit() vmapped_function = jax.vmap(function, in_axes=(0, None, None, None)) objective_values = [] -for i in tqdm.tqdm(range(len(sol["params"]))): - params = sol["params"][i] +for i in tqdm.tqdm(range(len(params))): # plt.plot(x, y, 'o', label='data') - fit = vmapped_function(x, x[pivot_point], y[pivot_point], params) + fit = vmapped_function(x, x[pivot_point], y[pivot_point], params[i]) + print(fit) obj_val = jnp.sum((y - fit) ** 2) objective_values.append(obj_val) @@ -53,7 +56,7 @@ plt.show() minimum_index = jnp.argmin(jnp.array(objective_values)) -best_params = sol["params"][minimum_index] +best_params = params[minimum_index] plt.plot(x, y, "o", label="data") best_fit = vmapped_function(x, x[pivot_point], y[pivot_point], best_params) plt.plot( @@ -68,22 +71,4 @@ plt.plot(x, y - best_fit, "o", label="residuals") plt.axhline(0, color="k", ls="--") plt.legend() -plt.show() - -deriv_funcs = make_derivative_functions(function, N) -derivs = [ - jax.vmap(df, in_axes=(0, None, None, None))( - x, x[pivot_point], y[pivot_point], best_params - ) - for df in deriv_funcs -] - -derivs = derivs[2:] # From 2nd derivative onwards - -[ - plt.plot(x, derivs[m], label=f"{m + 2}-th derivative") - for m in range(len(derivs)) -] -plt.axhline(0, color="k", ls="--") -plt.legend() -plt.show() +plt.show() \ No newline at end of file From 58efe74c38157e026e3cda389630286cc49d4f79 Mon Sep 17 00:00:00 2001 From: htjb Date: Thu, 4 Dec 2025 08:02:03 +0000 Subject: [PATCH 36/52] better timing of the funcitons and inclusion of a fast search function --- maxsmooth/qp.py | 120 ++++++++++++++++++++++++++++++++++++++++++++++-- qptesting.py | 28 ++++++++--- 2 files changed, 138 insertions(+), 10 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index a1e4555..786c071 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -74,8 +74,9 @@ def dcf( objective_values = [] for i in range(len(sol)): - fit = vmapped_function(x, x[pivot_point], y[pivot_point], - sol.params.primal[i]) + fit = vmapped_function( + x, x[pivot_point], y[pivot_point], sol.params.primal[i] + ) obj_val = jnp.sum((y - fit) ** 2) objective_values.append(obj_val) best_index = jnp.argmin(jnp.array(objective_values)) @@ -83,4 +84,117 @@ def dcf( params = sol.params.primal[best_index] print(params) - return sol.state.status[best_index], sol.params.primal[best_index], sol.state.error[best_index] + return ( + sol.state.status[best_index], + sol.params.primal[best_index], + sol.state.error[best_index], + ) + + +def fastqpsearch( + x: jnp.ndarray, + y: jnp.ndarray, + N: int, + pivot_point: int, + function: Callable, + basis_function: Callable, + key: jnp.ndarray = jax.random.PRNGKey(0), +) -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray]: + """Set up and solve the quadratic programming problem for maxsmooth. + + fastqpsearch uses the searching algorithm detailed in the maxsmooth + paper to reduce the number of QP solves needed. + + Args: + x (jnp.ndarray): Input data points. + y (jnp.ndarray): Output data points. + N (int): Number of basis functions. + pivot_point (int): Index of the pivot point. + function (Callable): The model funciton from `maxsmooth.models`. + basis_function (Callable): The basis function to use. + key (jnp.ndarray): JAX random key. + + Returns: + dict: Dictionary containing solver information and solution. + """ + + @jax.jit + def dcf( + signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray + ) -> jaxopt._src.base.OptStep: + """Run the quadratic programming using jaxopt OSQP. + + Args: + signs (jnp.ndarray): Sign combination + for the inequality constraints. + c (jnp.ndarray): Linear term in the objective function. + Q (jnp.ndarray): Quadratic term in the objective function. + + Returns: + sol: Solution of the quadratic programming problem. + """ + Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + h = jnp.zeros(Gmat.shape[0]) + sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) + return sol + + # needs some dummy parameters to make basis + basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) + basis = basis_function(x, x[pivot_point], y[pivot_point], jnp.ones(N)) + Q = jnp.dot(basis.T, basis) + + c = -jnp.dot(basis.T, y) + G = derivative_prefactors( + function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N + )[2:] + + all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) + + qp = OSQP(maxiter=5000, tol=1e-3) + + key, subkey = jax.random.split(key) + r = jax.random.choice(subkey, all_signs.shape[0], (1,)) + signs = all_signs[r[0]] + + # visited_signs = set() + # visited_signs.add(tuple(signs.tolist())) + + sol = dcf(signs, c, Q) + error = sol.state.error + best_error = jnp.inf + + flip_sign = jax.vmap(lambda i, s: s.at[i].set(-s[i]), in_axes=(0, None)) + vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) + + initial_state = (error, best_error, signs, c, Q, sol.params.primal) + + def condition(state: tuple) -> bool: + error, best_error, _, _, _, _ = state + return error < best_error + + def body(state: tuple) -> tuple: + error, best_error, signs, c, Q, best_params = state + best_error = error + flip_signs = flip_sign(jnp.arange(len(signs)), signs) + # Remove already visited sign combinations + """flip_signs = jnp.array([ + s for s in flip_signs if tuple(s.tolist()) not in visited_signs + ]) + for s in flip_signs: + visited_signs.add(tuple(s.tolist())) + if flip_signs.shape[0] == 0: + return (best_error + 1.0, best_error, signs, c, Q, best_params)""" + sol = vmapped_dcf(flip_signs, c, Q) + minimum_index = jnp.argmin(jnp.array(sol.state.error)) + return ( + sol.state.error[minimum_index], + best_error, + flip_signs[minimum_index], + c, + Q, + sol.params.primal[minimum_index], + ) + + results = jax.lax.while_loop(condition, body, initial_state) + + return jnp.array([]), results[5], jnp.array([]) diff --git a/qptesting.py b/qptesting.py index b83b581..858a952 100644 --- a/qptesting.py +++ b/qptesting.py @@ -6,10 +6,9 @@ import matplotlib.pyplot as plt import tqdm from jax import numpy as jnp -from itertools import product from maxsmooth.models import normalised_polynomial, normalised_polynomial_basis -from maxsmooth.qp import qp +from maxsmooth.qp import fastqpsearch, qp jax.config.update("jax_enable_x64", True) @@ -19,20 +18,35 @@ key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) -N = 10 +N = 7 pivot_point = len(x) // 2 +fastqpsearch = jax.jit( + fastqpsearch, + static_argnames=("N", "pivot_point", "function", "basis_function"), +) +start = time.time() +results = fastqpsearch(x, y, N, pivot_point, function, basis_function) +print(results[1]) +end = time.time() +print(f"Fast QP Search: QP solved in {end - start:.5f} seconds") + qp_jitted = jax.jit( qp, static_argnames=("N", "pivot_point", "function", "basis_function") ) start = time.time() -status, params, error = qp_jitted(x, y, N, pivot_point, function, basis_function) +status, params, error = qp_jitted( + x, y, N, pivot_point, function, basis_function +) +print(params) end = time.time() print(f"First Call: QP solved in {end - start:.5f} seconds") -print(params) exit() + start = time.time() -status, params, error = qp_jitted(x, y, N, pivot_point, function, basis_function) +status, params, error = qp_jitted( + x, y, N, pivot_point, function, basis_function +) end = time.time() print(f"Second Call: QP solved in {end - start:.5f} seconds") print(status) @@ -71,4 +85,4 @@ plt.plot(x, y - best_fit, "o", label="residuals") plt.axhline(0, color="k", ls="--") plt.legend() -plt.show() \ No newline at end of file +plt.show() From ccbc7179fcecf523d11b134de6dfda13e2e287e0 Mon Sep 17 00:00:00 2001 From: htjb Date: Thu, 4 Dec 2025 11:16:22 +0000 Subject: [PATCH 37/52] hmm playing with the solvers to try and make them a bit quicker --- maxsmooth/qp.py | 39 ++++++++++++++++++++++++++++++--------- qptesting.py | 6 +++--- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index 786c071..f8f3034 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -18,7 +18,7 @@ def qp( pivot_point: int, function: Callable, basis_function: Callable, -) -> dict: +) -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray]: """Set up and solve the quadratic programming problem for maxsmooth. Args: @@ -30,7 +30,9 @@ def qp( basis_function (Callable): The basis function to use. Returns: - dict: Dictionary containing solver information and solution. + jnp.ndarray: state of the solver for each sign combination. + jnp.ndarray: the parameters of the fits. + jnp.ndarray: the reported error from jaxopt. """ # needs some dummy parameters to make basis basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) @@ -41,10 +43,19 @@ def qp( G = derivative_prefactors( function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N )[2:] + G_scaled = [] + for i, g in enumerate(G): + # square root of sum of squares of each row + g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) + g_norm = jnp.where( + g_norm < 1e-10, 1.0, g_norm + ) # Avoid division by zero + G_scaled.append(g / g_norm) + G = G_scaled all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) - qp = OSQP(maxiter=5000, tol=1e-3) + qp = OSQP(maxiter=4000, tol=1e-3, eq_qp_solve="lu") @jax.jit def dcf( @@ -81,9 +92,6 @@ def dcf( objective_values.append(obj_val) best_index = jnp.argmin(jnp.array(objective_values)) - params = sol.params.primal[best_index] - print(params) - return ( sol.state.status[best_index], sol.params.primal[best_index], @@ -115,12 +123,16 @@ def fastqpsearch( key (jnp.ndarray): JAX random key. Returns: - dict: Dictionary containing solver information and solution. + jnp.ndarray: state of the solver for each sign combination. + jnp.ndarray: the parameters of the fits. + jnp.ndarray: the reported error from jaxopt. """ @jax.jit def dcf( - signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray + signs: jnp.ndarray, + c: jnp.ndarray, + Q: jnp.ndarray, ) -> jaxopt._src.base.OptStep: """Run the quadratic programming using jaxopt OSQP. @@ -147,10 +159,19 @@ def dcf( G = derivative_prefactors( function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N )[2:] + G_scaled = [] + for i, g in enumerate(G): + # square root of sum of squares of each row + g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) + g_norm = jnp.where( + g_norm < 1e-10, 1.0, g_norm + ) # Avoid division by zero + G_scaled.append(g / g_norm) + G = G_scaled all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) - qp = OSQP(maxiter=5000, tol=1e-3) + qp = OSQP(maxiter=4000, tol=1e-3, eq_qp_solve="lu") key, subkey = jax.random.split(key) r = jax.random.choice(subkey, all_signs.shape[0], (1,)) diff --git a/qptesting.py b/qptesting.py index 858a952..7fc2df4 100644 --- a/qptesting.py +++ b/qptesting.py @@ -7,13 +7,13 @@ import tqdm from jax import numpy as jnp -from maxsmooth.models import normalised_polynomial, normalised_polynomial_basis +from maxsmooth.models import difference_polynomial, difference_polynomial_basis from maxsmooth.qp import fastqpsearch, qp jax.config.update("jax_enable_x64", True) -function = normalised_polynomial -basis_function = normalised_polynomial_basis +function = difference_polynomial +basis_function = difference_polynomial_basis key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) From 44da19dfa91d22d93f1cf0bc2a63062c573ab7d2 Mon Sep 17 00:00:00 2001 From: htjb Date: Thu, 4 Dec 2025 12:47:37 +0000 Subject: [PATCH 38/52] chekcing the output of fastqpsearch --- qptesting.py | 43 +++++++------------------------------------ 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/qptesting.py b/qptesting.py index 7fc2df4..440d4d1 100644 --- a/qptesting.py +++ b/qptesting.py @@ -4,11 +4,10 @@ import jax import matplotlib.pyplot as plt -import tqdm from jax import numpy as jnp from maxsmooth.models import difference_polynomial, difference_polynomial_basis -from maxsmooth.qp import fastqpsearch, qp +from maxsmooth.qp import fastqpsearch jax.config.update("jax_enable_x64", True) @@ -31,7 +30,7 @@ end = time.time() print(f"Fast QP Search: QP solved in {end - start:.5f} seconds") -qp_jitted = jax.jit( +"""qp_jitted = jax.jit( qp, static_argnames=("N", "pivot_point", "function", "basis_function") ) start = time.time() @@ -41,48 +40,20 @@ print(params) end = time.time() print(f"First Call: QP solved in {end - start:.5f} seconds") -exit() +""" +vmapped_fit = jax.vmap(function, in_axes=(0, None, None, None)) +fit = vmapped_fit(x, x[pivot_point], y[pivot_point], results[1]) -start = time.time() -status, params, error = qp_jitted( - x, y, N, pivot_point, function, basis_function -) -end = time.time() -print(f"Second Call: QP solved in {end - start:.5f} seconds") -print(status) -print(params) -exit() -vmapped_function = jax.vmap(function, in_axes=(0, None, None, None)) - -objective_values = [] -for i in tqdm.tqdm(range(len(params))): - # plt.plot(x, y, 'o', label='data') - fit = vmapped_function(x, x[pivot_point], y[pivot_point], params[i]) - print(fit) - obj_val = jnp.sum((y - fit) ** 2) - objective_values.append(obj_val) - - -plt.plot(objective_values, "o-") -plt.xlabel("Solution index") -plt.ylabel("Objective value") -plt.title("Objective values for different constraint sign combinations") -plt.show() - -minimum_index = jnp.argmin(jnp.array(objective_values)) -best_params = params[minimum_index] plt.plot(x, y, "o", label="data") -best_fit = vmapped_function(x, x[pivot_point], y[pivot_point], best_params) plt.plot( x, - best_fit, + fit, "-", - label=f"best fit obj={objective_values[minimum_index]:.2e}", ) plt.legend() plt.show() -plt.plot(x, y - best_fit, "o", label="residuals") +plt.plot(x, y - fit, "o", label="residuals") plt.axhline(0, color="k", ls="--") plt.legend() plt.show() From a4d5774b4d02cc79f1a4f7fc8b9663bda31534f3 Mon Sep 17 00:00:00 2001 From: htjb Date: Wed, 14 Jan 2026 18:00:31 +0000 Subject: [PATCH 39/52] minor improvements --- maxsmooth/qp.py | 69 ++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index f8f3034..d9f0d6b 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -34,24 +34,21 @@ def qp( jnp.ndarray: the parameters of the fits. jnp.ndarray: the reported error from jaxopt. """ + x_pivot = x[pivot_point] + y_pivot = y[pivot_point] # needs some dummy parameters to make basis basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) - basis = basis_function(x, x[pivot_point], y[pivot_point], jnp.ones(N)) + basis = basis_function(x, x_pivot, y_pivot, jnp.ones(N)) Q = jnp.dot(basis.T, basis) c = -jnp.dot(basis.T, y) - G = derivative_prefactors( - function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N - )[2:] - G_scaled = [] - for i, g in enumerate(G): - # square root of sum of squares of each row - g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) - g_norm = jnp.where( - g_norm < 1e-10, 1.0, g_norm - ) # Avoid division by zero - G_scaled.append(g / g_norm) - G = G_scaled + G = derivative_prefactors(function, x, x_pivot, y_pivot, jnp.ones(N), N)[ + 2: + ] + G = jnp.array(G) + g_norm = jnp.linalg.norm(G, axis=2, keepdims=True) + g_norm = jnp.where(g_norm < 1e-10, 1.0, g_norm) # Avoid division by zero + G = G / g_norm all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) @@ -72,7 +69,8 @@ def dcf( Returns: sol: Solution of the quadratic programming problem. """ - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + Gmat = signs[:, None, None] * G # if shapes align + Gmat = Gmat.reshape(-1, G.shape[2]) h = jnp.zeros(Gmat.shape[0]) sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) return sol @@ -83,14 +81,15 @@ def dcf( vmapped_function = jax.vmap(function, in_axes=(0, None, None, None)) - objective_values = [] - for i in range(len(sol)): - fit = vmapped_function( - x, x[pivot_point], y[pivot_point], sol.params.primal[i] + # map over each primal in sol.params.primal + @jax.jit + def obj_val_fn(primal: jnp.ndarray) -> jnp.ndarray: + return jnp.sum( + (y - vmapped_function(x, x_pivot, y_pivot, primal)) ** 2 ) - obj_val = jnp.sum((y - fit) ** 2) - objective_values.append(obj_val) - best_index = jnp.argmin(jnp.array(objective_values)) + + objective_values = jax.vmap(obj_val_fn)(sol.params.primal) + best_index = jnp.argmin(objective_values) return ( sol.state.status[best_index], @@ -145,29 +144,29 @@ def dcf( Returns: sol: Solution of the quadratic programming problem. """ - Gmat = jnp.vstack([signs[m] * G[m] for m in range(len(G))]) + Gmat = signs[:, None, None] * G # if shapes align + Gmat = Gmat.reshape(-1, G.shape[2]) h = jnp.zeros(Gmat.shape[0]) sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) return sol + x_pivot = x[pivot_point] + y_pivot = y[pivot_point] # needs some dummy parameters to make basis basis_function = jax.vmap(basis_function, in_axes=(0, None, None, None)) - basis = basis_function(x, x[pivot_point], y[pivot_point], jnp.ones(N)) + basis = basis_function(x, x_pivot, y_pivot, jnp.ones(N)) Q = jnp.dot(basis.T, basis) c = -jnp.dot(basis.T, y) - G = derivative_prefactors( - function, x, x[pivot_point], y[pivot_point], jnp.ones(N), N - )[2:] - G_scaled = [] - for i, g in enumerate(G): - # square root of sum of squares of each row - g_norm = jnp.linalg.norm(g, axis=1, keepdims=True) - g_norm = jnp.where( - g_norm < 1e-10, 1.0, g_norm - ) # Avoid division by zero - G_scaled.append(g / g_norm) - G = G_scaled + G = derivative_prefactors(function, x, x_pivot, y_pivot, jnp.ones(N), N)[ + 2: + ] + + # square root of sum of squares of each row + G = jnp.array(G) + g_norm = jnp.linalg.norm(G, axis=2, keepdims=True) + g_norm = jnp.where(g_norm < 1e-10, 1.0, g_norm) # Avoid division by zero + G = G / g_norm all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) From c4dbd6c1a2e07097f749ea0fac6426b0b1de152c Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 10:31:51 +0000 Subject: [PATCH 40/52] prevent visiting previously seen combinaitons of signs --- maxsmooth/qp.py | 70 ++++++++++++++++++++++++++++++++++++++----------- qptesting.py | 6 ++--- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index d9f0d6b..a1c50e0 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -58,7 +58,7 @@ def qp( def dcf( signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray ) -> jaxopt._src.base.OptStep: - """Run the quadratic programming using jaxopt OSQP. + """Run the quadratic programming using jaxopt OSQP (ADMM). Args: signs (jnp.ndarray): Sign combination @@ -133,7 +133,7 @@ def dcf( c: jnp.ndarray, Q: jnp.ndarray, ) -> jaxopt._src.base.OptStep: - """Run the quadratic programming using jaxopt OSQP. + """Run the quadratic programming using jaxopt OSQP (ADMM). Args: signs (jnp.ndarray): Sign combination @@ -170,14 +170,13 @@ def dcf( all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) - qp = OSQP(maxiter=4000, tol=1e-3, eq_qp_solve="lu") + qp = OSQP(maxiter=50000, tol=1e-3, eq_qp_solve="lu") key, subkey = jax.random.split(key) r = jax.random.choice(subkey, all_signs.shape[0], (1,)) signs = all_signs[r[0]] - # visited_signs = set() - # visited_signs.add(tuple(signs.tolist())) + visited_signs = jnp.zeros(all_signs.shape[0]) sol = dcf(signs, c, Q) error = sol.state.error @@ -186,24 +185,62 @@ def dcf( flip_sign = jax.vmap(lambda i, s: s.at[i].set(-s[i]), in_axes=(0, None)) vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) - initial_state = (error, best_error, signs, c, Q, sol.params.primal) + initial_state = (error, best_error, signs, c, Q, + sol.params.primal, visited_signs) def condition(state: tuple) -> bool: - error, best_error, _, _, _, _ = state + error, best_error, _, _, _, _, _ = state return error < best_error def body(state: tuple) -> tuple: - error, best_error, signs, c, Q, best_params = state + error, best_error, signs, c, Q, best_params, visited_signs = state best_error = error flip_signs = flip_sign(jnp.arange(len(signs)), signs) - # Remove already visited sign combinations - """flip_signs = jnp.array([ - s for s in flip_signs if tuple(s.tolist()) not in visited_signs - ]) - for s in flip_signs: - visited_signs.add(tuple(s.tolist())) - if flip_signs.shape[0] == 0: - return (best_error + 1.0, best_error, signs, c, Q, best_params)""" + + def body_unique_flip(i: int, fs: jnp.ndarray) -> jnp.ndarray: + """Check if flip sign has been visited already. + + Args: + i (int): Index in flip_signs. + fs (jnp.ndarray): Current flip signs. + + Returns: + jnp.ndarray: Updated flip signs with visited ones zeroed. + """ + index = jnp.where( + jnp.all(all_signs == flip_signs[i], axis=1), # type: ignore + size=1, + fill_value=-1, + )[0] + fs = jax.lax.cond( + visited_signs.at[index] == 1, + lambda f: jnp.zeros_like(f), + lambda f: f, + fs, + ) + return fs + + flip_signs = jax.lax.fori_loop( + 0, len(flip_signs), body_unique_flip, + flip_signs, + ) # type: ignore + + visited_signs = jax.lax.fori_loop( + 0, len(flip_signs), + lambda i, vs: vs.at[ + jnp.where( + jnp.all(all_signs == flip_signs[i], axis=1), # type: ignore + size=1, + fill_value=0, + )[0] + ].set(1), + visited_signs, + ) + + #jax.debug.print("Visited signs: {}", visited_signs) + #jax.debug.print("Number of flip signs to try: {}", len(flip_signs)) + #jax.debug.print("Flip signs: {}", flip_signs) + sol = vmapped_dcf(flip_signs, c, Q) minimum_index = jnp.argmin(jnp.array(sol.state.error)) return ( @@ -213,6 +250,7 @@ def body(state: tuple) -> tuple: c, Q, sol.params.primal[minimum_index], + visited_signs ) results = jax.lax.while_loop(condition, body, initial_state) diff --git a/qptesting.py b/qptesting.py index 440d4d1..c5ac53a 100644 --- a/qptesting.py +++ b/qptesting.py @@ -7,7 +7,7 @@ from jax import numpy as jnp from maxsmooth.models import difference_polynomial, difference_polynomial_basis -from maxsmooth.qp import fastqpsearch +from maxsmooth.qp import fastqpsearch, qp jax.config.update("jax_enable_x64", True) @@ -30,7 +30,7 @@ end = time.time() print(f"Fast QP Search: QP solved in {end - start:.5f} seconds") -"""qp_jitted = jax.jit( +qp_jitted = jax.jit( qp, static_argnames=("N", "pivot_point", "function", "basis_function") ) start = time.time() @@ -40,7 +40,7 @@ print(params) end = time.time() print(f"First Call: QP solved in {end - start:.5f} seconds") -""" + vmapped_fit = jax.vmap(function, in_axes=(0, None, None, None)) fit = vmapped_fit(x, x[pivot_point], y[pivot_point], results[1]) From 6ecd1e162e2f3f03267f714e62daf206521c372a Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 11:33:13 +0000 Subject: [PATCH 41/52] start the qpsignsearch with some good suggestions and move solver initialisation out of functions --- maxsmooth/qp.py | 96 +++++++++++++++++++++++++++++++++---------------- qptesting.py | 14 ++++---- 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index a1c50e0..b5d6835 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -10,6 +10,8 @@ from maxsmooth.derivatives import derivative_prefactors +qpsolver = OSQP(maxiter=10000, tol=1e-3, eq_qp_solve="lu") + def qp( x: jnp.ndarray, @@ -52,8 +54,6 @@ def qp( all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) - qp = OSQP(maxiter=4000, tol=1e-3, eq_qp_solve="lu") - @jax.jit def dcf( signs: jnp.ndarray, c: jnp.ndarray, Q: jnp.ndarray @@ -72,7 +72,7 @@ def dcf( Gmat = signs[:, None, None] * G # if shapes align Gmat = Gmat.reshape(-1, G.shape[2]) h = jnp.zeros(Gmat.shape[0]) - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) + sol = qpsolver.run(params_obj=(Q, c), params_ineq=(Gmat, h)) return sol vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) @@ -98,7 +98,7 @@ def obj_val_fn(primal: jnp.ndarray) -> jnp.ndarray: ) -def fastqpsearch( +def qpsignsearch( x: jnp.ndarray, y: jnp.ndarray, N: int, @@ -109,8 +109,10 @@ def fastqpsearch( ) -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray]: """Set up and solve the quadratic programming problem for maxsmooth. - fastqpsearch uses the searching algorithm detailed in the maxsmooth - paper to reduce the number of QP solves needed. + slowqpsearch uses some elements of the searching algorithm + detailed in the maxsmooth paper to reduce the number of QP solves needed. + However it involves a lot of conditional logic which makes it slower + in JAX than the brute-fore try everything method for small problems. Args: x (jnp.ndarray): Input data points. @@ -147,7 +149,7 @@ def dcf( Gmat = signs[:, None, None] * G # if shapes align Gmat = Gmat.reshape(-1, G.shape[2]) h = jnp.zeros(Gmat.shape[0]) - sol = qp.run(params_obj=(Q, c), params_ineq=(Gmat, h)) + sol = qpsolver.run(params_obj=(Q, c), params_ineq=(Gmat, h)) return sol x_pivot = x[pivot_point] @@ -170,30 +172,58 @@ def dcf( all_signs = jnp.array(list(product((-1.0, 1.0), repeat=len(G)))) - qp = OSQP(maxiter=50000, tol=1e-3, eq_qp_solve="lu") + signs = jnp.array( + [ + jnp.ones(len(G)), + -jnp.ones(len(G)), + jnp.array([1 if i % 2 == 0 else -1 for i in range(len(G))]), + jnp.array([-1 if i % 2 == 0 else 1 for i in range(len(G))]), + ] + ) - key, subkey = jax.random.split(key) - r = jax.random.choice(subkey, all_signs.shape[0], (1,)) - signs = all_signs[r[0]] + visited_signs = jnp.zeros(len(all_signs)) + visited_signs = jax.lax.fori_loop( + 0, + len(signs), + lambda i, vs: vs.at[ + jnp.where( + jnp.all(all_signs == signs[i], axis=1), # type: ignore + size=1, + fill_value=0, + )[0] + ].set(1), + visited_signs, + ) - visited_signs = jnp.zeros(all_signs.shape[0]) + flip_sign = jax.vmap(lambda i, s: s.at[i].set(-s[i]), in_axes=(0, None)) + vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) - sol = dcf(signs, c, Q) + sol = vmapped_dcf(signs, c, Q) error = sol.state.error + minimum_index = jnp.argmin(error) + signs = signs[minimum_index] + error = error[minimum_index] best_error = jnp.inf - flip_sign = jax.vmap(lambda i, s: s.at[i].set(-s[i]), in_axes=(0, None)) - vmapped_dcf = jax.vmap(dcf, in_axes=(0, None, None)) - - initial_state = (error, best_error, signs, c, Q, - sol.params.primal, visited_signs) + initial_state = ( + sol.state.status[minimum_index], + error, + best_error, + signs, + c, + Q, + sol.params.primal[minimum_index], + visited_signs, + ) def condition(state: tuple) -> bool: - error, best_error, _, _, _, _, _ = state + _, error, best_error, _, _, _, _, _ = state return error < best_error def body(state: tuple) -> tuple: - error, best_error, signs, c, Q, best_params, visited_signs = state + status, error, best_error, signs, c, Q, best_params, visited_signs = ( + state + ) best_error = error flip_signs = flip_sign(jnp.arange(len(signs)), signs) @@ -203,7 +233,7 @@ def body_unique_flip(i: int, fs: jnp.ndarray) -> jnp.ndarray: Args: i (int): Index in flip_signs. fs (jnp.ndarray): Current flip signs. - + Returns: jnp.ndarray: Updated flip signs with visited ones zeroed. """ @@ -218,15 +248,18 @@ def body_unique_flip(i: int, fs: jnp.ndarray) -> jnp.ndarray: lambda f: f, fs, ) - return fs + return fs flip_signs = jax.lax.fori_loop( - 0, len(flip_signs), body_unique_flip, - flip_signs, - ) # type: ignore + 0, + len(flip_signs), + body_unique_flip, + flip_signs, + ) # type: ignore visited_signs = jax.lax.fori_loop( - 0, len(flip_signs), + 0, + len(flip_signs), lambda i, vs: vs.at[ jnp.where( jnp.all(all_signs == flip_signs[i], axis=1), # type: ignore @@ -237,22 +270,23 @@ def body_unique_flip(i: int, fs: jnp.ndarray) -> jnp.ndarray: visited_signs, ) - #jax.debug.print("Visited signs: {}", visited_signs) - #jax.debug.print("Number of flip signs to try: {}", len(flip_signs)) - #jax.debug.print("Flip signs: {}", flip_signs) + # jax.debug.print("Visited signs: {}", visited_signs) + # jax.debug.print("Number of flip signs to try: {}", len(flip_signs)) + # jax.debug.print("Flip signs: {}", flip_signs) sol = vmapped_dcf(flip_signs, c, Q) minimum_index = jnp.argmin(jnp.array(sol.state.error)) return ( + sol.state.status[minimum_index], sol.state.error[minimum_index], best_error, flip_signs[minimum_index], c, Q, sol.params.primal[minimum_index], - visited_signs + visited_signs, ) results = jax.lax.while_loop(condition, body, initial_state) - return jnp.array([]), results[5], jnp.array([]) + return results[0], results[6], jnp.array([]) diff --git a/qptesting.py b/qptesting.py index c5ac53a..0d3c1e0 100644 --- a/qptesting.py +++ b/qptesting.py @@ -7,7 +7,7 @@ from jax import numpy as jnp from maxsmooth.models import difference_polynomial, difference_polynomial_basis -from maxsmooth.qp import fastqpsearch, qp +from maxsmooth.qp import qp, qpsignsearch jax.config.update("jax_enable_x64", True) @@ -17,16 +17,16 @@ key = jax.random.PRNGKey(0) x = jnp.linspace(50, 150, 100) y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) -N = 7 +N = 11 pivot_point = len(x) // 2 -fastqpsearch = jax.jit( - fastqpsearch, +qpsignsearch = jax.jit( + qpsignsearch, static_argnames=("N", "pivot_point", "function", "basis_function"), ) start = time.time() -results = fastqpsearch(x, y, N, pivot_point, function, basis_function) -print(results[1]) +results = qpsignsearch(x, y, N, pivot_point, function, basis_function) +print(results[1], results[0]) end = time.time() print(f"Fast QP Search: QP solved in {end - start:.5f} seconds") @@ -37,7 +37,7 @@ status, params, error = qp_jitted( x, y, N, pivot_point, function, basis_function ) -print(params) +print(params, status) end = time.time() print(f"First Call: QP solved in {end - start:.5f} seconds") From 390b41710326bc8055588f0068579490a81531e6 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 14:24:55 +0000 Subject: [PATCH 42/52] removing old files --- docs/Makefile | 20 - docs/images/Basis_functions.png | Bin 48632 -> 0 bytes docs/images/Gradients_fits.png | Bin 20645 -> 0 bytes docs/images/Parameter_plot.png | Bin 57499 -> 0 bytes docs/images/Parameter_plot_extended.png | Bin 100303 -> 0 bytes docs/images/README.png | Bin 54160 -> 0 bytes docs/images/chi_dist_theory.png | Bin 10357 -> 0 bytes docs/images/chi_distribution.png | Bin 18525 -> 0 bytes docs/images/combined_chi.png | Bin 45499 -> 0 bytes docs/images/inflection_point_example.png | Bin 19767 -> 0 bytes docs/images/inflection_point_example_fits.png | Bin 32039 -> 0 bytes docs/images/inflection_point_example_res.png | Bin 72311 -> 0 bytes docs/images/routine.png | Bin 34057 -> 0 bytes docs/images/simple_program_csf_residuals.png | Bin 51426 -> 0 bytes docs/images/simple_program_data.png | Bin 17989 -> 0 bytes docs/images/simple_program_msf_residuals.png | Bin 50615 -> 0 bytes docs/images/simple_program_psf1_residuals.png | Bin 50922 -> 0 bytes docs/images/simple_program_psf2_residuals.png | Bin 51595 -> 0 bytes docs/images/turning_point_example.png | Bin 22523 -> 0 bytes docs/images/turning_point_example_res.png | Bin 68252 -> 0 bytes docs/make.bat | 35 - docs/requirements.txt | 3 - docs/source/CHANGELOG.rst | 22 - docs/source/best_basis.rst | 45 - docs/source/chi_dist_example.rst | 59 - docs/source/conf.py | 111 -- docs/source/index.rst | 9 - docs/source/intro.rst | 3 - docs/source/maxsmooth.rst | 93 - docs/source/new_basis_example.rst | 169 -- docs/source/param_plotter_example.rst | 84 - docs/source/simple_program.rst | 179 -- docs/source/theory.rst | 180 -- docs/source/turning_points.rst | 121 -- example_codes/best_basis_example.py | 45 - example_codes/chi_dist_example.py | 49 - example_codes/new_basis_program.py | 168 -- example_codes/simple_program.py | 233 --- example_codes/turning_points.py | 176 -- example_notebooks/Data/x.npy | Bin 928 -> 0 bytes example_notebooks/Data/y.npy | Bin 928 -> 0 bytes example_notebooks/best_basis_example.ipynb | 1512 ----------------- example_notebooks/chi_dist_example.ipynb | 171 -- example_notebooks/new_basis_program.ipynb | 280 --- example_notebooks/param_plotter_example.ipynb | 260 --- example_notebooks/simple_program.ipynb | 394 ----- example_notebooks/turning_points.py.ipynb | 316 ---- maxsmooth/best_basis.py | 249 --- 48 files changed, 4986 deletions(-) delete mode 100755 docs/Makefile delete mode 100644 docs/images/Basis_functions.png delete mode 100644 docs/images/Gradients_fits.png delete mode 100644 docs/images/Parameter_plot.png delete mode 100644 docs/images/Parameter_plot_extended.png delete mode 100644 docs/images/README.png delete mode 100644 docs/images/chi_dist_theory.png delete mode 100644 docs/images/chi_distribution.png delete mode 100644 docs/images/combined_chi.png delete mode 100644 docs/images/inflection_point_example.png delete mode 100644 docs/images/inflection_point_example_fits.png delete mode 100644 docs/images/inflection_point_example_res.png delete mode 100644 docs/images/routine.png delete mode 100644 docs/images/simple_program_csf_residuals.png delete mode 100644 docs/images/simple_program_data.png delete mode 100644 docs/images/simple_program_msf_residuals.png delete mode 100644 docs/images/simple_program_psf1_residuals.png delete mode 100644 docs/images/simple_program_psf2_residuals.png delete mode 100644 docs/images/turning_point_example.png delete mode 100644 docs/images/turning_point_example_res.png delete mode 100755 docs/make.bat delete mode 100644 docs/requirements.txt delete mode 100644 docs/source/CHANGELOG.rst delete mode 100644 docs/source/best_basis.rst delete mode 100644 docs/source/chi_dist_example.rst delete mode 100755 docs/source/conf.py delete mode 100755 docs/source/index.rst delete mode 100755 docs/source/intro.rst delete mode 100755 docs/source/maxsmooth.rst delete mode 100644 docs/source/new_basis_example.rst delete mode 100644 docs/source/param_plotter_example.rst delete mode 100755 docs/source/simple_program.rst delete mode 100644 docs/source/theory.rst delete mode 100644 docs/source/turning_points.rst delete mode 100644 example_codes/best_basis_example.py delete mode 100644 example_codes/chi_dist_example.py delete mode 100755 example_codes/new_basis_program.py delete mode 100755 example_codes/simple_program.py delete mode 100644 example_codes/turning_points.py delete mode 100755 example_notebooks/Data/x.npy delete mode 100755 example_notebooks/Data/y.npy delete mode 100644 example_notebooks/best_basis_example.ipynb delete mode 100644 example_notebooks/chi_dist_example.ipynb delete mode 100644 example_notebooks/new_basis_program.ipynb delete mode 100644 example_notebooks/param_plotter_example.ipynb delete mode 100644 example_notebooks/simple_program.ipynb delete mode 100644 example_notebooks/turning_points.py.ipynb delete mode 100644 maxsmooth/best_basis.py diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100755 index d4bb2cb..0000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/images/Basis_functions.png b/docs/images/Basis_functions.png deleted file mode 100644 index 89f35d0b0818c2b310532eddd2c32df1a481078c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48632 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Ķ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 z%0D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 diff --git a/docs/images/Gradients_fits.png b/docs/images/Gradients_fits.png deleted file mode 100644 index 0a716843c2717620b19c915d9b82c9dcc731867b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20645 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�i)kU!ij=3rV5;i?)+v9*Q_1lY;VSV)GWI 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 Zf%7dS51kJhh^4DC*l4&RTgUdq{{rK?cX$8* diff --git a/docs/images/Parameter_plot_extended.png b/docs/images/Parameter_plot_extended.png deleted file mode 100644 index 3939d2f0dab904e63cdfcc293c051e1112366873..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100303 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

)tZjwy<};&QOlo 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 diff --git a/docs/images/chi_distribution.png b/docs/images/chi_distribution.png deleted file mode 100644 index 889b4b8a2a6ffa7c8ebe90c05e43b97f97189db6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18525 zcmb8X1zeQvwm$sKkP?D|gd&WB1=1j)z@Vg{2ue#Rf^L3+@AhgO#avBJNB_If9 zkdhqU5pC)nf&WMy&nsV}gg>5?w;sdmJ@!hvjtD|`1O1Chlu59FH^rUgb)2r+nK`-M zxMPag+;FnDwsW$!xQTNyz2j(MXDiGn$R~IjXYS-=FUimUuh04H?%d|5H)Cc+5FDZ` zCwuK~#B`s}-D}IfbMuXLw~o_$-#;(1=OSX$X6BoD{#~o)`(KZm?xZ>C>**iTd6q`I znSE$Vt1$4L6_1ymRaa3Y@2X42hnW?MZtm{MPnS3!-@K3f%%FUF=vfLqg)~ zHWkBO(u8x72!{*bZrEHtcdjBr!m+`1ElOG1vvKuN6^jWe45;IGw*mZz#4%&&5v1Id zk^nFGE+FukJu4Q6AcR_a1cM;gA0m_pGAKlfhtETgAXo&+r}>YUjC2|x2~XsXy3duY zideRubUVjh^o#^r`N9(W@`Re@*4q4n`%9||P9!RJwckUH;kasM5ewY^L%-YDVFS?`caEX8YG=(#|1I z`OImsFv!0<;_J-F>fAuaL`#Cc&qF$n^h2B?kj)V>`8T^Y^89<^!$1KHlfTOa?o`hK(7?v+0Td_KevIotnGn z9P9?j{bVn_5mByqNZT^qm6hW-){tN2zBcqI$7!PZJ)aPQ;1wLMBi2?{S9Nv6?|nAz z?GUr=O`M#xOw-L$@K~8vhqsw{_2M`c1HMjoz|4$A`xtf@`FKe_rA3e+LADNx%$S(- z2M!$AF5MaQqqF?>^nhNeX91VR_QtaNLd}Wg9~bB*(u-z4t$1wBSLN6bou@r?#=3mb z*~uv}HnzgOzq^}T*?nSAaQ$tOh{N?Lu8GE~ZqajtEfWpDC1j2}(liY0dXV%#?zf&d zZ|td`^uK#p($0@|@{EKZ&Lpv!|t%|JN*U81j za&@*(FUK+@r+#YLa%XEjIVI&;*XqzCj&_^8zBA*39q9%s9&;smjVq=y13Y%Kl**%Z zOpW1X(Q_t3RfAjGWuq;D2VKr)Purf|HFgfEF;&}Y;*9+eDkqX4;7&7^l$7+bh*F6j zZu_KF)5F8#dqb!uCbOVGcgSAn!Gi~aJ=E0HId%imQ*J6M&s=7ElLoeDUH#Y{+mbbt z)6;XK@^W)6zuez5x#OE|82B`6<~qlWdqz*=+{mY*?X3o$q8EyEVjD|s$2!E*j|nhR zCB?@pP&1tl`sc1iN83~sloX_i5l~-WU$?Zhyl6hq+k5@j=;&UDCrG~XSEadJr{p-} zSAFsl{N82JSBB_YLmau#Nm8kz#j+~N%KCar8%5i9w6?~@#Kgn}9Ht@H)YD5|SXhV) zAVH)96<<;NRYBi$z(}wlZb0wX-i~jfCXCtyeV8!LGpu6p?vOww^jHZeQ-+-`Sa1 z;<0Ku-T9IG)G2jm=NxVx9#O|p)%rK0DpT!gSM~MZigJr-C^E!aV%QE z8s@kvG^`7To7nH{3{0&awDDSTt1sDzrIJ4vz+KeSAfsbodZ&xQt5Ge=OGRz&Y;wkR zkEGYHL*tgl_8}2Gut5xpTrB#F-P#w&k>}sPU$p7WlvN4kYio*C%yD0~JS^?0(~_Xp zF%J_ByNZ@1;FF+Uc#|LwK&b_Ztf&!oyxXqIno= z|A>%LRCVbj+s6VfB*@eYd8Favg|yp3EFK3~S-2sC(vlpyk3Q6DLaIExV>Ov|FL zDMy@k^Jn4??fL8TcVzVV<42I=kDt85aQVsN5TQL70a-9jK{VvPNHrH2UnM{M<<%{p zNCSAj!iiw<2j%pU0x}vL1DI(XZA>iT!VUOtCdXeF`j4M9-axR`q@?Aff|R6qp)G$b zd5|oa`5^LkxgTiT7~%``nKJR26oafVB`IP1&v$V2wiuFX1ihS!1uw(`w|YsBFnm2} zjMR*WQv@ND<=$w&NK)u7f6(l;I7w?M+^6zBALlf{-hOZ(5Nbu02`^XGC#h2>@#G2UH4N-a| z{2q8Ci)LX~5kEWvm%@vim&ogRjgd3xoV>B8X2Hkf&}U1j*kNYS%d4bM9y54F$_j%nVF|i~$ECcGiZh|4gdXB(urSVQ`afMjZ~UhVE#*ix zql61Hg7hARm1Dxwj9jU;5IvJ;Ay=M|+mN{|USNEm>zmiibQM9{J?mR+=uU!s~JXF!9MHF~6XdG*jv+{hOd?tr0@#j^#| zC4n!#N3+3N5JYa!Q<67#_O{!tk!U<8ZU9>B5#(q<4H@UiGEFH*5EVK`2CGxz3K-6S zpIbv4D<=|`HVYMlPt*{?>I5S^y-$Qng;b3{mnKdUgDeBGZ{T?ge{&wYhi357ZyOHv zP9--?M)z6HH`jtrD7zOG^mVrn#12?xFL#ZJu1*GWGtNhJ2sU`Dj+VGY%e?&O6lfXj zRJ2~VBHq6pTWKump0l?xLPV=yeD(gb#Yc4R5m!#exh_8c&esq+Fej5?vUDPRwcBe) z_4KB(b6XFk+IVrJ*BLl=_&205g?@KsT1zfFm5)6?v_rTC&3|KU zZh3Kv^+IikwvLHOESS86=4Opck&>D=Ha0HIdkEBWo5(>i9wfW)i_4PSLO33x{=oUv6e#QVD-h23K*<|)Cyabk;>C}Xb zl9e}G-eu{f8s-MtU?us2?hO3t@JqOp?yuJ^~e^oUM#)IZD6F%a^z?Da+7<~979l6|cn?5o!vb)41Pb*E&)MnAWEz@jm-4S)za;OB zJluOayYxyDdUqo$4mclJQC>)N zsnt3lv84EzXR_w_vf{a5PfLmZ)PyK^?ulV_?S>ah203|o3Dcgs2avaK-yYceNK;3L zC95Pe^UCJR%uB9cBO~KGn{yqa9oIQc{F(T!C#re=WZ3>6@aK(~T~y`sLt-Kvq^I^# zJ-BxDYAm2#8p$Hb>0j}Mg}ZIHTU|a~;3$~1yQX)pd-i7pgIL>3gPl*q@0Qx7FR>WK zO=U!T_gB47j~Ko_$?eW8bl?*=a@;brr@91iP-W!t%DL6W4|gahzf1I9(cTgED)O%y z>uj8S2y+=a!G28ST+qv49~1a^e^Sb|c2lioA>NZGgBr)K!k@a8`1s?1Z@aE>Bjfub zsp7Mq$>PR&Bq{H!m$O*H$Vq$&W_4ljySw$Q^ttw{+t{Ry)`h=p{pk1k-9;4@O+&*d zYe7uD&fKp-LYA(|XK;WQ>KyV2YLSv3NGSH|G#)y1D93fq@cH4hTE~tZ16ZhKYWl&f zAtFgP%gmy$&>28hmI7IHMshMY80e&&98CavHQqD`-vI;K`xeIZbi4#5=Kmv}!60Yl z>@bh=$^6C5F>;0Cd`Ls&S?x-i;>R0+Omgo0`YsYeiR`bE`@!;9be{-%dbgN4Wx;3$ zQTeiMATd6t$sRcY%1BI3zDP?;o1Br6S9B6#t2;>AEc!c=CZ9p&^AUsmF9`1WmNdEV zJD+Uir~zux6?`LRji!6C3g^&w*u*Hm@_jbG0*@j4&e<5mKGXcSm2}tp3%m(!oxSn< zFwxzT6?+4TPP>aSJT57S#OsTC5%ee$Ia1m8eMfg*}?1SB}; z8P5x0A16vKIPW}uQMx>yBH4OJvf!SnZvfx%dkXGEoOJMQ z595tNyRt8p<1?c!MbB;&?bSnG9KU`8U=eh!dWzLkCU3#*99aI_u7cKz)VSsc08mh@ z;19k8?SW_1EaUi#5s5~;d56cN$t{4}tNh_#@bpa-^b-}hAR^rQ1pOR;Q_J_Gr+!Au zsssN0PJOqnpH+FSDSdULL_t5=%P_jYJ8EkuBCcV#sBbrxVrT6kUy1Skone)%JwCU8 zU?0O;0n9rvMi;o}Yz=9&Q<)ee)kL3X?9Z(m3!B@@kv@~(Ot_pW4u3Jqv;TUMad!6P zMQYr`gW4qZ`{`y&dH4k5?>ed7$?Z9;AIDtM_r zY?#WfOdJM4P>>4--fL=-hnahnLW900_g&g&gJByT(-wZnuFVR)i{T|0?2Dy*#-%dZ zhppx{rjY^^gqztav2}E5raJiq3^ntgFEYrgkd~i>CAy6Eik1e6yS&7d$@PGR^5~y$ z>D~iRiD*;}&o7;(P^5mx1>ZFU4@}^VNh7@HBllI(pn${1nJxrxZM9qCZoE|qW`zz^ zgi#)}0CbLY#@rS%*F!!S^7snu6KN(ur;VSD-?3l9Oe?@3o&d(kl;=zF{R$|3;;SY( zlKCKdnPB2{zri0HPe%WzjiW&oyo3Gyb20Fp3gUM}>2SP+V0S%ag5L{c zmoWaaXsaowWm8G9NRm89xegqwNH}PSz5tat6Lj_jv9snFe{>T6+`sXpu@?3PoEUe9 z5Da1s^Etv~FGidfbgZf9N~i=&!nnM>MNP*4eCZvTz{56d*ag@Xh5>y*IOJcA&q3JX zxKxgwc}}_3+Ri$=>Tu^Xr7}dIj&61yw?ny-emNz??Q_`{Ek`9mWEj;yL<%XZ$ z@;J{^E&=v$j-&IQ57W68`rq!%xTP5gX{yw!Gz`<=Z|0NHz*LoYc%`(=GL?fpVA$)U z;d=M%fJ5z*VzHZXc2XP3dvhYB8?z8Ufa{3$P~(IxT~-mDv5BMpmmz+Gf1FC+(+cRq z91S|cAgcy;B;)q)?dF=Xd2!p1MT&q)73V=huJ%;oJ^OE9j5*+uF{#M&If`n}iGe{pbjKqB@Vh9L4wt$Td)}T{|;GvZv%k zc#uN5UmtNE9?1B?hp&%xbMLuzHr)vpNhpa-pqow*kK9+W|3CtZSX~qGAV~(N2U4O`P7^l#o)WXR`}5L+o={j~paD}-gd1p7UI?)(w%%)hVN<I&4?&b&3WO6<1oX2IQT!&nX+Qu-bOL|0S3!y6V<9=W5sQ5)B{HH8%QGx?Tw3 zZ{JREnd?u}OwrQqDK^X)ZH&$+ERNiJ65d2`a$gr%hxwJG7~b=9(}>qRbU zvn8wj(mi?BT`|SQ#jQS+an}JZ_sQe$CGy->GL>>JoqIXbl+_d6@m~9?OQ++C%$(aX zx15Y2Q7PxT%6oAv1E+7i=RdAm^?cZgnqm$^hxuP8W=FJp^Wc1PQc}}B zGU}1l%^AMEOq& zdnWuFlKdI0!q=q2U-IhrPC-Edgg7%9@U~xo6L=sC&rMqrok%q^Yi*Bx7 z#6<$-5bDs&J9stW@{vCweCgKclZQa&AXS(fGQ@O!Vh`9hB+hU&8#QWS6(^1JNdQ9_za77b zbIC;xnv9cBb`Tps&Y*>zc)H||KaPCiCAK}GyXR}Eg|Yj9cRU@g_a2WF%9jyZYwt6a z_vb}}A+ZJGgdUg<+;XaV`I)`gClA#E6&Kw05bP-cZIqu0Z^CwZZAuI-ejh%9d^wDI zyB<;@V|M%~a{rJ+4j5<#8_aa(JX2;4mD1j_{X^_To@CIlNt#gABe~Rk)<<3cwhkw@ z6vJ_X**}O2Sd(woJPjP)hNk1;Btbo8_H&Tj_3C@6qdB{?Y9*81b4*1LVhhqcM8LLrJR>ohI2Hcl44_iuj zHB>$A$D$*@pMrV@aOmNT4ZCb-6zs(Eq8B$~{P5hVF&_+qaiU9)i~S~cdyvd zJGzZR;1L*NI&>PCfZ@$?skye^;4mu{Sa`x_wtj4WeCOEJ1}mJ>30UnTV1^Ovtn6aB zj_WSI;03h}%Trbws^0}RX_dZtcs$K}OVmJs``rnxoqD%GtQkFJ?_<9TI^YGoeutq4?}0~+ zln`Nj`0#<7pC1iVkY&~0-tZCbqes9|Q6D>u_-ytJOkUvF2(rx|A_u2%>8#6ireV>q z*ZRRyo|UkSNcCwcUP4X%u?i6Z``EaQ6+5^DwdtVIq(tv5B@`~V>o2DmZC?z&r6KW| z0YOUSI`&;&VX_y&3&DBjnvg}cBhUnbv-ai#X2V2~g1X$LU8Z%~T3g4LJB$Lm_9A%h<=HIerx89p#=!Fq zomZwPH`@BiT=@G7wMi}+7PGz4QPwWpc<$x&5C(ai;`+=$XdAhZjeL0!T-wcFx^@#H z+HcmIEzvt%%7v53DZx_b5X9jdX*rhywuOS;R)kA?lUA(v9VkK0E-rh&K`TMvd*@Wk z%5IV0%VcEhHCIYsvFXX3pz~StL!(t~BQMce=|_7HHz!ChC%qS!LduV&79cP85PGo> zscCE4q&-%wXS%W!K}fvj=2pNCe92Uf5?2i92B=YKl-``a65*``uo<}(b*+w!rNoQP z7yv)mL!mqZdVWQ?cKg;>eRf?#UcE|u_YRMmv{c=!S1(`2G8=iS8*Ma)I&G~v zh@Lq!*{*MQ_-P9Xa{XvGHmvTBeLId`4;eao;ZBavl>R_7IxW!W$a8KQ&d$zYR$J)2 zf0Jx)mhBe7i?;rLX~qO{BwxvCwlt31_Xh<%A3B-61&+>*Qmf+&wfup)v?CllLmb(T zW0z;Tb5a@$KO;y)%Bv*|7p%|25lbHs=+b@-HJovtyatlW6hrjd{q%y-H-9E|%Mhse zF_UU?Um7kkF>R1YTA)kDRTCIQ_ozFyc({e}c>{0;s~?vwjWUgWBNHeP@d#&X@h2z& z{l^-y@q7T>Ml=oZArlzWu}5&u>{DNzCUYHKaX>BezH}FaV6uL-8EbwsfGi)QeHJPI z7_+^?LW+$zl)ger<|iBS`ZXY=UWnU~21-~sd&B&0hHL-Sf_e-Xk#bhBaPO6b77>@S zP_Wa-ug@Sz)nqt@KsZymuovP8TEHrh>pTQr9Q{B#L5xK$Tj=#{d6{TP1XX^6%3`Vj|os{6>^wI((Vrmh zvljH4xtbBhyC&-lI#jkM+p=lyO9$lr8B1zBR{Bp2%r$EcfTkX*+Sa@f{QlJGAX)Q8 zazwn{*b9M{bH7Bl9^Tq`_H-Yo*Hn|XbK)EpLyG3E;)8 z{lP4%$u|-F(Xd5a%ZXmehnE0!!uWMF*LfnD5c)I*!-~??-{rh=K=~!+0@$ZU$>QeU zu0LITWHl3 z(rXbi5$`BE9A|h3=RC*GZd5Bu-*gp35M`EBI^%0=bxQQFJxB@*gpktp(YM`scG2A2 z+|!^s;PyO8C$lEQ!>3#l0*Gx-?xknU{Ov#>|C+y>ZP5}hy-E5%lANsl^W>j-I4={2k-JCt@oFv-@m07`Swq7EXVvZPv9$%ITGycn8gqrDiOp z(w#wE5I{4GU7z&Ypr78yn-5;|8}TXYm3fy$c`hhRE&aGqIF(+s^o5##T&!&UIlJ4) zzDP;ui(uMg6$9HR+fs(vGh$;e02psyY;V_6);P%skBdVmE+orOJ#zo<*%~5z>!y^O zs_Sp+2b?6Yc^LP)?tY^wHp;F3T6o^`k9Zv@ILbDv)OZ?L??9=QFzNLgwTr=$XU~R& zh9;n7d;1yX6!Q$(+p|9gZ0AsfTG`ok)Qb(IzJARFnGTXkCKBmn z_PGCv#6hajPSg7UUSZ13$|~i!YS=pfffk^PDu*y%;Q3z^YMO8zH2^p{?yFkzBTX?= z+#82~ZSMBF$x3!5>;4j6{#eVeK2pU%e(rqyc`dSX#~kafPqM2u_4S&z zwzknTpj`8ZTz~`(Sp$g+$J?&F<%a$f@SD zh|6*odnT8B7zO>~p?v-Fgv*i5z9bZ>W6z&I?=Eu9s0=uq5*)lA;*t~q&fx1>!OLXZ z_DSaC$?>LGy%G?DIHXe{Z^UYGwBC#SA%cAJ8|XNUP`si3tx5vw ziFgG-_}SiqgVv*OLU^<-e|--*C1nS}20X-jcST4biDYrJ*j5ueMhiH8!&1XQVU z^h9GTQszvZzbj1`66Pg9G~fix%43*coba(`3IR_umP~K}7-iD(`=B8sLN5V1`XXV& zzdG1)px7aM$5taJNW{x=LBGQ%Dyn_(Vx^F3rKpmMau0YrPry_GOw|$qHn-YIxIo#h z#L*+ws(#BDkxCt+DC#u)HV6j@6L0ou16g4}V$*zrM@$$6a479%FP=hYEaQhSbf>^` zVCaKTkMW3_Mu?K@ra6YRfoN>I!CpfY0(c=v4mG~L##R_bN&=qaFBVhirBBd@LH9f) zc$Z-NkM~-P8Dv3{_c9DT2lO~}42HrSNgnSQq+Z^;LxxhtNWhs+-of#61b>A5&+FIb zNZorf`pmyRJV&^}U_cRuP|Bf~2fQBFu!mKVq9p9Od5{GLxfAi#7Sn>ITtc}&kauyy zv}b5(U|Nh&rxZ)JpN;gVDWiZfno`A9uSb11$c<y@IoYDtYm>g4X>be2TON?FS!EvU5m~dxX+WCHw$Z>w-5+=|^ zVMduiL`6O+IBATh8`gf2*GEbq`{6X)9p7FpA$-bd&U6SUQ`l3FkHYkRdMMLSSl(n| z47-ZB*18piWW82*%Et#Fx`hRVuPBI&EZbuIBf=?us34?&ni?-4gM%bM4<`+0wbn?p zG>+2Q8urA^_wQJ1Fz?yG(h zfSuh#fZ%28J4wvi888+KYShLVA$V00q+5dv$2sqeAh(`J++~n`WB~`EG7q4>D0aRb z<)g>_GDx61UyZ0i%^$S(JcJ;+oK-!pr}7123BJ;Q-9n-T+u4=}te_;kL5Wl!ZDK0F z62XM$=Oqvxpl=+MaCm)>I*Uo*2L;ONL+kOr62erS{~A0iS+6Uvu^!^fPMp{A|MvQE zIvLv}(BUkwNI1sFt3{`ux*9)zLT3F*pF9?cQ@R}S zVX!bY1P@Dm4Om5`JoQ)w3y8cR^#RQ)idPMfIi~X39K4qcGc6JnhllSUg%rhzdS_mO zbhH`>qQP+i0ee|ZZuzs0K!)Rq>W}fh6Kz-)$e6h8cpd4@wRy|LZ-&(*X`d;66|j4qA}EfR*~&bmG&l zJWy+)Z$!B}&u25wA+V#V={<~^=;66eF;cl+CP$rD&x=9GA0P48kg8kp3ukTV#=l z7y@bVoaVkwO+u;n3TYm1W(W6`+WssgC zGaev4@Yggv?SG*90NBhYVWL*Afh2hQAGpKn5%+^k<9yoMUv*5+wUAw@5X$epaO~w2 z)kmTh{b3lwyf}zgrK2+%-v#_jipCc%rIPhJricNC$szc%|6L&(xxf|F;(BykzzRd+ zB|gja8~9w5g_v@K#1E9r_-Im<92Y0o*4Bn%%(`%4QLFaTY5IAWAr+)Oac~hL><_>| z=H%vb%gD%d1!52utQHs)5Fb!${qE5)_Wz1r)X;+p=5pf>kv^P#r;?X;y+8xfpIZf4`O*sUQ0c^lt$|t#d!Dt>&{Wm3=;4Npj_|QF# zj13|UFsww+21cBBFbv|(JU?A()a#If{aZ3)c%wc`A8w7Y`S+`4;r$u zF7kiyfhs+kjkieVPF8OI`hlqv&k}3v^nt6 z9h`J6

v?y$SwN3sW)Ay^ZZ}MJKgOKDN&yTeA3ich7gFKfMe7Vc&kf zNS)^vTTs{74)01%WZTcIA;;FIHPFEKYEHLqv7J^AM14c(eszIpgpmrEBP+F6qjIt& z;{hefMvg?>CACz*3>rh213T!s{SdGh4<5IXyp`R@k#06+0q)Z|(Q5{JLWg$)lz{jQ z?}8}S0S=nJvPS<$T=S<}(%N>;4(rT*h$XSqvL|DdYsMak@E}IxjahM__3?5sJhN(* zTeA9GSE~gV&H985_g(o@!$UD4u83sEJKt*$hMSD%!RPifq z`Oe#{Qh$3dcC>##Hfr(_Ch3I`H;9X`dB}SbcgXoLm`j;^ep{lw-z6p{kw)e4{kx5+ zks&&N+w>6c2yOgC1TNNpo-D1Y5_%Qi@tK%4D8N`Ua{xlpOYwyI zJV-Up^D*w;hY2X!aD+S1X+) zFgDvE254xUNI@H$Hy5DQ(jJOj*2O*VAlvGXy!Y*0PL?`rwClt%kBA*g9A=i6)cv07 zXA{oG32UW()im&zsPW$uq6Jk>i{j>>&3(kc?7I&iOnx1bXYPf-=oXqr%=wxaqL`2+ zl$6Uvio^nVK-eF*fQQ^$IQ!lpkyw!hQc|G@OFNIJK_zd(gXJ`b1vY>Xr8i!nJi31^ z%gCXOwYQpwIfh3F1wiAMH6lNOEUZ!3KwVyv=0RO)EZf_GB*5O}IKxHDa>Z8w^F z_hr^nJ$$l@2y>;$6F0B3bq^w?(NR+E`wwu?6hPK9WR+ENfzA#rKYylZ+5l^Pw8o1I zq`dgCa#*@Fsj%eUZJDyyc&Mtc=(}?)osP3^1w?KOQmox}*c7b|J0_d!Ugg3In6)O^e{t`+5&tEUELFv9}gpKeo(0Q3?_=Hlr*yIoA% zSN4AjupS8l!E}uSgCQWvXHS3F4$yfdV_&<1UfK*+QoxXj*!jK8_LF1(q_c~B&0MF{ zwfmm|%3tgu12YHgBUm^9K+GF26Ll9Z_>WDP(>Rj??qpYH`WqUIkZU%L2(XUvYOaopZvAI#_w8H7Y9cUNAQ8oZCHW@_uO5|#wLL-r2I^&4!jY9 z-0Q9Rej6-{h5V|n;qj6`YTfxj)D(lc0Us13Qj^C4}D5hI@A7^pjqsR|ts z^Xl*47t0~nm-CG-#^Gid44Pp8@#r=vm@V7#=X)ly3zvLtYdC4X*6!xfXOyKFJ_d;t zfO_K{EH)AYUWrv@{L@ zlz}-;CqZ9(QE%`OJPg~PwCn5ZB?8U_vDQWes+Bb~qNk9c?@DH7W>43;UMftq+VtYP zuC_}~KAYqCZ?_h9Xcvv*g`Z$>2)y@yy4H*TUmwBj1iY&a-TzGjS}@GGLrB0jtpB5A z{v*IpQlP@%0`tgUzL~ zoARbgM8(96eqGH*?FIeV->=_5`duwV_1hX*S>^o7C{01bO^HLIgF0<%)6Xn~gPNVU zEks(iZ4T<^*-C7kOMCfJ3ztpH0nuaRrF&rD<3;S>zki$7npBir_P#ojGo9-}7@xP7 zloX=OvT?J_@bp5Y3^gtVguL>7U_a{lcOASVF*xG%2dwXfI9y;263NayA zWGhKQi-?H8Nl8ilo3ypGzB|^3hivMJLNt$)?8ECPY*}CN_gmJ(I4M6IgW{~<^!|il z_{d6yP8Z5O!EP`P8w>Ptr_Dt0`~2Xa&tc|Psv4-}e^>^_cKZR7 z#>N_qXPxjcAHgpg{&%9~^So54tXz-~0M#*ZuwXD47M5PA!Bu$edVr&Qx6(=XM$+*9$+aqXFRtX0$r7YrvGq&}+9i2RIiRtAQ}W^vi>MZY>Im&}`tcRt5V}Ne-aM+fycOMFfEu?< z5Xb@Z6nbN1(q^)@8iE^u0ZfGh0_znAA}1OSLv_n?sDw>N(f; z@<)Z^|MHr=P^vC+}S~VrqyUbzTR@qr_|02x#L6UH;11*PAlQ1=0a( zQ=CtHT-*l8^!%C7Sm`QQ$uMOr=X3KZuPV2FL8m#37dIpKW`QE1i1SY+{ZoZB$`E3mg7@A^is9Bv+-N@WiA zu`+Q8WX%r+LsXi*xUG4lZ-NFRUzTpR_w$QDruB)464{&;$8tAHlDzrsnxx!+cJFyu`3*|n_3RM)R( zIbb|h1V`)Cs~FMda0nur4VWAY}T1zeAwe?7j(L^j$g(E?MKPB;K0u^U717OQZ z|0pVgVA@yU;5ZL~rf!mp{tpcP3$Oqn{!jn$|BsUY&Hemuw_}MIe8MKtCj=Zott<&_ zERckL#7P-<3}CD9y^)ye!-oj~07kbdqWj;$xS0_`>5?$4hxi{=J~oO@~N#2pa!OR<)rLh zTVn$iim|Z(V-#3yT<7uGlE*{tq*4R@6u`m(3{~*s?d=U99dXWNbFJCC8eBwFOXu(w zA}8mLT@w)*8IItgBottYH_!XVK^tv~1%|`yheK-2$B*p9p)~P>m9@3P>vFibxEN&D zD@{JNG$cMlBtPPei6=#SFr1y;pS>x7H2Q2vkUg`Pd0?P%sAn&}_2xy9!(#?5OyjmY*-a3ht$qra5(X+6mGU&`==v_c9 zq_V5L^>NtKM%RHjz%xw>GkXMuF`Jk1W*Sdy9kOOe)_Wtdv2rdC9MuM}YI3O|DeEA| zT;WZX&IQ7pu|y1639F&L3J6307XHIHrr~>G>5oRkb#KG`ZR}!7shNC+1PRZM5#-jM zY6_yeqcU@c6tc6mfNYro!w0`XHlou*EVF-imsd(!`X^=kXGCA$Ye)23DjuN8Z~bH} z4J1}TwP`FimiQ#V{mRw_<&>jf++j{4QI}|x#&Pt~@z}OkT)?(mCo`?O+ciik*DVNw zUX!uNl*nkEW#a!{n(vgx+Lob=W3g z^yWaGcTWOM=Optd{2+XrrxFh1e3Nbyn(01w9F zf8A@qw8oXB1`vwqxO8RCN#uu9+NBjVgR{Bwo!+$(%&i+AyB=P16YlHiOwN&PXP;fY zqD$*@mXwr)2{e2wQX47ejOTA*+_SV*LV_)ML>)wt2KZSrTwa2MXJz=J2_NlGeLvll zAFVsZ%_l(n-lCTUn5q}{2$f0ubBTn6!~{71df9|Wyde`kEsR>79vfFJSZiLql&)Ocu-~C|BxB~Vs;2}*Q1zuJNsl<+ z4a1-Q+SOf0ed?UH%=ejISjdpKeC@2c)bU|R{Iyre<&_xl!#ONVE91FPg^@*_I7C#b zEQq*MnLr2v^aVKo8bM+p5IQ=#p%9PAJ>A+nbO(wWeXY-S8g_IgBZl#nXu=O`^{H=% zF_RTL7ia4{OrcVE-ac;nrQ;hnwUp1_*7)!p3U;ZTlM@KQ4W7DQ7TDzlGk5Z4^J&1n zj3413FU_Sb!-9c@j}IcBq7R$z0E-3gjO>nLICD3Mn`99S5uugT$w@uq%i23`tW>e8 z07*}C3?t%Y*ZyQGyu*i@T@-P1{RZia8}@vlgRtyixu4C-QAL!L~BU^-GAtt%|8_ZQ+zM4<$JuG ze&mtQ(Df?!alKiMoICLy5LVp@Zf13+8-oyX~IEeq9gHltU%c9!i zFq|ljF^);{m8+O}s-i-~XLomFFOl_g~i?Q3HS+ zzm$6j9RB(O9e&wt%m1&@m(Zal+z43;J$g{#9T+eflf=JL^k-)q%dO8Oz;sVVdimwc zmlp`mXDmrJJayQ#N70uaDT~$!yJ@tsI?>IqUV^uQQgCE`0byfel_QUkp6A86XB|Q@ zJw%|W4x`NU2Ngm52U>M)ZA-h$K$Z%Ew4>4ji(2-xYY9PMs)vh(@k^(IKQTV&@bI~7 zy&**k)%(kA!6iGc8s>u%Ire^A@)Hj7pafmB61IhjXteLhwwLNCpUq`u`bZDPP(j!U z{Pr8K9N<+z;AgWMvSRHlg?sNdh!BCY{o#Khbzo11lHJ|ke;~t>7Gb~m%_7}Dy_(l(oIoyoy=d9HpC zEd^-~8fYo=$ITH02v!nY7*ZGtYjh z;6gn<5>irjP*tJ4T;qqfO`3XYDIdA)FACdQIuH&r9ex3>cW+M-%tcP-ZLhUfP)!`0 zR~>+NKILQ}p+9$76ujgrT~wsUH|PnN=y4R^0HlMcQ5!GnGH?;!K`fJ|4ENKS@sDO( zC0OD8JHjwYpih4)+eMpWN$1@Eu1z=L&G2eg}&;IBnLsUN&4kU-&-osAv$K} z{;n-8VFth&w27V_ucBMB^;WeP=^oJe(*@a z5*zH+{C-LD{4wrLvXf5&y%0mp+Mhlr2ynoxZV^v;<`PV9`LX|f2?8JBaKUs{=?112 m1~8~vlbBfS2%EChYw|6TOs+0jh&C4Zr>3H%T%~0F>VE)|%xWzF diff --git a/docs/images/inflection_point_example.png b/docs/images/inflection_point_example.png deleted file mode 100644 index 6f1da4388fae11fe3ffe2cc9fc7e55e8fadb967b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19767 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 diff --git a/docs/images/inflection_point_example_fits.png b/docs/images/inflection_point_example_fits.png deleted file mode 100644 index 03dbc1767020760c96ceccba542a5aecb6520dc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32039 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�CB;jfoFe>2Y~>r~SX944ynM|G^{%z_(O zNt`l+WC>``#6SUg`SNA|y&q1c$HCxoUhwWj2fH7GUktp{zICp0e%SYBw~^uf8&NC= zOS>`4n$yEfRR$hLsOoMS3QZ1?%Y@Wy2ubF_zq`>ztym)z^_{vrBVJ@X_~1T~AE2l5 zuZ=;(pfKCPfFtEuPP|wT$6Ok&1_BOm_u1uYZ#?y;yH26jPAj4U#l$zuRE9o#nnGn2b?e-yPrj!(mkb|d9!MAb3v)R?HM8*FT}8Ve_)l*?C$o&+ z=zF8neiQbrL8~G2Sb3eyYi1V(*wrmQaHmQ>$2@5B6gTV_eb{@aWgj(Lmdk`RdQDLT zrMwqUsqcFrE>@}T;slMe@E04-(R*wP)UdNLTRpVwfbiUHEb{z6m=!Hh2M}1Fd>jme zQV0^bWJhFTJc+_)<#E9P1nSMlDNti{;jBCz94{$9T{z29d$npwrVL%CccKJ3D3v%} zIf(~|^kV2*AfyunndF&(@=?jvSSzWQWfW7?*;JIYl$3xwuxA4ewok zDR%z;=&1xklM)+TkVPwv>HT4nQk&qB`05tP_-E?z zGFJcfZ}_f{Z-TfYiC)|8BBtpFkdrTa#wpRa<95mJ^=@W+(})=8xqR*(>M8rYD+DtU5doJiDXHHP~v6#~G5z90U|$OP$al7Cmh7Qt|w-){R#mQ392 zRjkKNT?neU26aQOeVl6&Hl*1SSB>!;z}izuF+4@&yh5=hKcOk$anqGGk(k3?GeO+i z_nv>L{x9vyrvL0aCfxON%D{iY_}<;JCd(HlINf|xN7YD4!lDf?6&W#kfTDHATa4HK zA!Xi&T@PQ8d+SLbz9QZH8;tSpzcGG~kXI8u(YjB#%$V9g?8)2HnIT@to=(Kxgy>jX z6+r~)ThV*wFC61YZ5luPnG`w>;Z4wr&mg)Z7kW45KDukd>ArWV18Vl{^4`-O&`1a^f&cyOV3QmAJ!mZb967-vv9&C7;K->Q4oW<11MH>F`1#ug;KH?!uPdBIcLj zR9XYNY>rymx}XrFUtltobVLFvlV%sT^7Y4bmc>%_Hg$f4of@gl(c=xm9-oQ^wB+Ny zJIe9qL3=Gk@!%b|Cq`dpxxTP`34EyDWb$yS%z}k*zvGYpNdoQCvpq>r$2tUsG186DJ#zK1=!UXTE?0g8PwZsohAMO`JQ=q_buazJ~Q9QX*jP*?{O5Kc-O(2M2Ds&35jN<u0gRY%~)&-|0FlOw8Ap zUJuy$ZAK(eE9y%<0F;daWqWuhVyau-!?LpfH9xvD-d2JY8ono+bUV$DPjd9|rqOLc z?6Lqj>Fr^qGT199w3(DFhZjkiz0#i3vm5T*)EHa=Jxew1r!*y0tOeN%41FQRTL#6v z3=x`iVmVZ-=+z$9PB~PT4(tuX_3EdQHO3QL8}HwCIgZ_4tJ(O*EFW=fDc}R@U-T1@ zF&<`Co)^N~V~sQ#qAz}_su$PzDKazvm*n|(}nX! zL2{u#e-d!6h12zx99dZ7oYtIh${FJ5Hp{S=&KHiPt(y*^t`UPo{0GK98h z4y|u-7L#mHi$KHmI*>m;29B9A!G9>^21jnBg$#O{63P@)JD$Q37x#O|$Qsr7;b)gP zIW)wn)nAcO4E=d&y2_*Y(}hO|UBv{&n}O5ty-d2SfT)Dx%<>RX`|EQ^wguk!b1tE> z*aYf}U|jE_PLq@M8UNPB-)(ev)8d)gGnI=6JXPxZ8asNFSQ{hFH|@f>v$IrlCDwEY zw)jDDxXK8ZY5weWSVU`(Y*10eB2EJ`R#BqtW z1g1CmutAO?jxV04wyqn5`c<1ZV-kNpE0jjx?KD>~=h3M*f`mhipwnw&vf?)lP&JAv zm;i9+btj%-0J$#yXixm|2%sQK{BYmIK6j2xSR)#L5$`Y~^nzDc9KI)w(qs^vHEv~# zN)2&tu68J*?b;&wE|B8(R3R7DIOh%*e8jYk7Q_X9x9xwI6n~y}NwM|vnkP3?KZ9@w zxqK=H`pJu2a-#gcTc1_Lyd?XS@xKLS$b($NP4G#SF?}N!tC9g@7F35A6X3qdR~|PQ zY9_@etapjWwfxL-%^fIlp-iKU$y|h_dg7Ji%o$-=-MQBeg5$wRnmQ$@WX_HkjY#l%M)NL;*#$s*x>o#Ba&ocBT(MaD01C>yIZbi@|XLA z+(H|3TV}EX^F}Tx%Z>Vxb&AN~6BM+@qjtqLE#%FM1?=#issJs0*Yz6CH+k;FTI|zX z_XS!eS@CBAxJ2IUj3-WQDTzb865|wklrdv{F=@}`p*(F$tWl*KG=Yr^agf%K_O4;T zXBk1oZ=H42FDsvKGP=xG@BqrU{d-uvr_o^@?#`F6(0e2L@VR>2kQSq|U=DWg5;9FD zx8VhCgVSxd2*hK3Sj@6eVn6oUzcm9Qy!tR(zo86{l9pqp&pKLoP&g~e5=I9-9xk^` zO&?j?FQakAyKsADaq;z2BoT{#CPB}-!&xkuJhC^IZ^N>*J3|FS0Vp2?lK z!sqXku3e4raU1lsAz4{)B|6jnJnH3xEfS&XGj3z$4lv0fcjuw08r;L2cj6_I=gnNH zF?a%G3(r~~?xwoSh zv@O9!actwB&1>DJbG$Td*Uq)Pk*;EYEo3ycQhWg${ugER{58s-J*@9rFU!a0gxG*Y zBhh5HXwe5wons?VtG&H>!z#4J>82hByeOtE)h!^{gR>RJATbW(stj47zQ?LlsDuj{ ze2)V(dOsc}sE^#diMVW}MAOoO{di=yBIFs5c-AT70nsSwMa7VBalz&)A(Xb~OM7$+ zuS6+Xmd&Kd!qN)rU%t&z!oim26LylhzQzwjy*eLS`@~Y7#(s7*5O5Q>gJG|cJr!fw zl2!lrup_tY9sgUkpqle8L%>kfhGcZIB4b0=K*XTIfR_y9{|vaT z`#BJ?DNA|>G0s%*o~BLgWdrqg1wsA@=qfme0m%$8%Lq|b`|uqe04K|%x+O8nTSbD% zo<2A@_7C{_A*oQlI6bv*#ZXa27?Cr^`hJ;lk3Os<+x42UuL0%qRnoePk41034yD!@ zrjvt_cJI5PTezSwZw85%?8U%n@{%#%7;3&xbsgD%XOZe*%OYQQF7B3%!z`pIoJtNY z+=b>O-+x8scBBwr>}+|>kqsRs1ajahG)W{qmyJ8Apdb~pFwj_3@{Guax5Gw%>UCcC z!E*&FF=nsrC%zA-Suy5)uXqTsYj4GRzspoW&@9s(%i+bAmiHlrHkWqw-pQHa2Xl ztzt~K?eAg7d1=VwQhwu#W)IhO{Z)MEpjj_bhkLq-G$_q@{e;8so(LL7!P%n7T-?6j zrGy^lrmx);J|~}#$VeN7aKHNUTFWT1PdOo>im>=RbcSqMae71Zw0>5IHG_z)QTyue zK`q89UD><6h0x7~S;$d3@!FqTPxmQ!;V@T^c2Ej4vytpb;%A5TWH7uBSz*J>)M!A<#KK^+jS>D+4_!W71 z>p{X*861vbeZ_1Tv=~fPft0BuDw*Hb0a5(MEiN}9moZx3&N0Jv${I>GzZe_zhrCW` zA!?CznAj|)WcPf=6tlXU4EM*Ea2Y|QSt2c5;!)SpvASqZ6#|6@uyGHq{eZ=}XJ^Ty zLy<%5A%NCRG$Roh#Q)X=y!iHOFu+FIc!aQ}OAEas~D7mUq3kMULxv-w~YcoT60nlS`U77E^`AdCFn}yIn8ard zU`s3TypXwU_j=;^me7XLPgLg7!!9pEE=1z6Se?YMvOLRN$`LxSwXQ$Ur}Sql5>ZRS zm8_JI{Q7cjZznl4$)c9L0K}`KkB6a(I=q2K7_x^ZbOhSm&__Esb};uya;w}?HFjhw z+Y}EK6-_SUmHDtjd?W5c15+=3**=3RIo*UkXc9?oa?f`O&fu^rf}&Y5EoeNSF~YQV z`R8ah{Kn?`{+6csA`wRB!DX?>Pc$s9P=*|SDl0f=Q*R}{1V{r_Wo_MT{Omz>^YF9``2P?^ota{LMWc%+JVq1yP+NN*}uA!4Vmtf2bbVD=9; zSVhTQia%mpB1jPyKpR8~VwMqY`4mhMKe9&{=fhpP40oUYSR%)T(JB=#dyX*u_kIJ~Hi{52%^}keXSPIPU;9H; zvebba@`0m_T?d_I`$Y5{B{wf2FMou02O`##!39?j?YdSe!^!^j+gk@Q2BjDWQC zfzM&9#K!JS!f`XkFMFE|6I*(*gpo=Z{3&>8jNB00-5tdzcP%WWPM zMgSMuVt2Hx2;ob122fkiR1=PVA`>r2)9a0>=BXaqlnneEWdpO)egDq7K;{Qbc&olL6Wq|6YXj7#XskJQ8l1 zMds*8`H0=*X#@5JI)~ifS;B>vWoO^TjUxS-cjhRm+BpphD|6K_&yKft;v~3i_+KS) zydey5C2gwf8MN|LHc{-cRf`u&PibEw5KlvRbuS(WLm#0$asixh?-e@LCM;u|Zo`b+8~EFZ%Hifb(hvn8OfH{W;SE4z(8ml1dTY*(-gM)KBz__X>jroFUw8LU zgoUDMULi*SNB4ZZK5&{h&DT*XPg;}Mp%0;AKm97fe|{s~vU$NM*YA!cnjY^OM*KJl zE>Mig_$jYSYjj6I8s|0fi9V-56uWt)dylwukdyjh5QKya4yz?D@`N{VLvQlM_duzav%?-K6(mcpnTi=4Z$bp9ork zk47)U7ax4wC0!q9w@-xgjVjnvq+yIW59mF9_BPHO@k8hlx|zO7(68FQ#UAt(L$&{;#=DZ5Kayt`G@T{ zEMHg(VucbcLXZ>=u6md0Q(6U+?D;~r)pDvqe+tH!#hc#}Wr@JS)fD1o>ecJ|d1*ps zd4H1r$#X^sD%c}SvX8%2Y{j*Xj+%?u)Y1F+_!NBn z*i~`oTmRIQ&9=fb4Y-AEkc?Igb4W@GtB6$v;&^Z4Z{T{idZf7fq&)BhdwYAv4dE@3 z#5mWy$g|tZFszZu5&a1a%;`6^7VvUIfevFmT2Y8*jb(QWKQ$L3W1 z4iK5@_*?!h>2h1oTPeNrwcMx3KtWc>{06E9-s<|=wG07JI1u=_#>oI^e?3=Ladh_Yi*tIrQ7MT8D!f$mvp zNZQfH|9}kjaMF&l-;CwBK5^VLD}S(F%5lf%SEb+9ZD~02-dJ zxWWSJ#pBJv%?q{v%jIy{ne^4uBR4KIHPGH_3OX)XYB*XgCQ#+Fi-b(gI$FcYVGxgY zZ2NxGeq+ON&{}DA&bxPQNBb-JnN+_VmQ@u{v*G}z|AqYmEesM~6(ZdF`SITE;gm5L zBLi={^~Y{kMsJ!SE0W4&y@Haz}bZ$%QOy9zcJlT5hZ0pc^Olf^A1O;A9|v zt1Z>xu7jzI#x9NvxWa`L=UoD8@-Jkvv6cQ4rBn!Pgd1e4a6D%c>twL74#_-Schbop zvTO=e5N+7L8p9$*43)W!iHca)(8MY4F&oIwA^v}y1y(k;8x|Ik1XU@orQVKb{28Q> zg4%S;Qd-;DRuaFC189*=%Ho2NXO{5FL6Cq0Gx6Yxcdnnhc+Y?| zCFtoOewZQos_77iir_E0=+OIKtKrYUlZM)bEK*1hw`GCv;tFQ}_C~A=tQGe+Ndh(C z{G{*v)23nm(0J8-Hv95qp9vt~>Yyz9R)4-ns;~ViwTk7lDKW~n60$Jrqd$j`Vk)MA z2s29B%3P#^1ImR!pm4hyczd>5^!UX^&cko2iKp>h^U{%IIY2(xCAJ(tsAuRJStb_`# z5!~E`Np?dF(38P@oHI-ZQ%Y5ia5wF$RpN;4kFm2OVKrSf% zEOKp13nI%4%sYd^9O=a}s&gS8`83aO4PL zL-27rWpOqMa7NOT5P7=d1Up$WM-9qH!PjMoOcW34%j$V7(c5gzM@6!0%UhdS#d9v{!xD9Ntr;(fi1+&hb zu6S_@$I2gxO%c4h2b+G)N?G@TK}||ZN*sv=Ad6tD&M;u|qDmmTH?8dRvf@vXT>qX) zc%1RjkY?rPA{V;ix(MR}4q)#08{4YQzPpu{wGS`xT~7%Egl4PCyK{2Qhc6u1ZdKiD z`QeoLfc0VixLX8oWdo`%@XWQOiE%mG>__{(hHJs`8t~ z!vG;`%r=+p3a40b*=peinds?{8wn^4@MD7D|&of4C4j+18N_;mbf2{o- z_u|)2#(Buc{Owhuj-=ucTJ^dGjKP!BHCuHVgzK3nn#IpN|Nt0aS6%{VBf%pk~>6 zyww~h)pzB>`8M@AZeyaF2qJLK!CMTL&loE2(s#zNJU#roM1*b`B`|+~y)>LZ-Jj_? zT*{2=c+PZd0>W8}M3@zu&oMP0Agk{E2whxUyq&oZw89CDb%NOhq}Z?_LsgFRv#s;n z!%i{}rmv(0?ft0vopkGu$|6BV9(?~(ZLT1CpbaldrF!C#_Gs~~^Zom~fhT}b_rg)~ z8DY`50=Hr2r8mP}p$2IMl=WulG0f94KP*|wO_fk#rZJ5Zn zn)9<`7!7i*S81yq$P7O2NmpWm#2@`}Y}n~!^Iy)6^jIy-p9dxmBhA_Y02JAE9wr@= ze1p$b!9XH(4zOW6!?ZXHPlSWMQb4NX^v_C z1xn%B$MetlJpk4K+{N|D+6!@4{*Z#L=koocZMi*iw8ZKufs9QMD1_!a4rZTH+mDJ! z{wYabntHs|XxZQ|;a<1G=hi$E`1g9`Rja7i!WQ<6J#P;dxXzt7l-}j%lMt}mPOq<1uCbP4RATn#<|!p1)P@ zQ_=|Lu|50jP1_ulbmRfE$4ZE!&v27iC?2y=Sk&5_Y7>OreiW zIpEXM9`Bb?=s)-IbgmLbCF4J0D1g(Hur|Rb^6m;UtdTfcbyhc@-Y3v@4}Oj{Ejky- z?+%+NXG(c3>R$mk6<{C*A*_uJ2f-lttc@yUG=nKk^9WVGO4uZl1o|(b#{d8VglO$A zy0s>-g%~63u;*u|3NE8p>HjtmFz!b6jPK;$=&c6~r>v0plM{at+a~rIpwudH=PUi% zo}ft{X3VGLRy9>5hc7dfm^WQ!M??_a4V|c8Eh_dHF|(Kh4|jlhjv-*IE)GBTj7N(s z`f2jCMK@3OqdVHK{;vaLNPurjwb?Ol8_l2m?TgG2@CV4m=+>?0AcmPG#9P1~M{_9o z&QAHwbPzfs2qp+}>0e%7ZwE&>ig0Ykn}U?ifL16uAYu|hfj}^{waBb^d)UO#4*bu5 z8_Q*g@8nza$@AS5;7XP<9*eryZ^+)8s$&4nI0-&8!-Xd0AnYUTLjq%S2hcqi0MWJO z>uX`c(k%vYbzIr{>GrWBMaIno*aSNecoJ;TbA$6glL2d`5F zQ%|%OK_H{YUiqVw2Dq=|Wp?Vl3zPr$8VJ281OrA;;_gY2At#*K?ewj{{Ju;p2L~Sa zro%;cq7C59BP}Z&$(qh~KQ7cP#I_Oa5aG3*ot?KQW9^u0K(JHV_h@yv(0{vy1co;@ zrfkC#IK|);&epAcP!9@Hc2qb|Y#p5cKl{m%s=e4QdFaOv5SvBE#!?NBjJ)3O2=)&qD*DXTI&G zR?RDYTyGnB9@{#$NKciF3^g_x*qz`fWqE(o6G-{-#oIsHOXcUzkd1KM=BF_w0;x^( zHVLTvnLC1QO%3|6c3)4Eggln|i^@~2c(rtP>Qp6Js0yh$Uk&p0q zR@D+Nv8$F3NL=Uk z4FM0q^lO7uTxr>-kIoP+>9ts1UH{G6rLTW(Uf?%qH+=HvWko|02F={`-%}x(WjI<2 z?$M97)S5T8bH#!R`}#^9XT5*ic>~hd&?; z59Fr+G>sshnws(lo_(9(2yBlA-)sYiDYPWfr+R*cz^LY7rm+9jogfd`>kyQm?#rrj z`0D}zZ^iR|F`fd%WM6i#9*Nld|GE42XBSFmtR(QypGaz7~yldKUyjdSK zeGUL_Ho&{W79T_oY6#IRFg(%#Z}J(WMF9&w;i>x3F(vQW#DiuIkOKjei%*tt@BqHz zX54kYmzDq&bjET#2i``(YjKu3_&_~#-v&)Xp-On2?u$qf0lFcCvGVV8r<9r2+KH$1}yZ!(*@0=ZPEdZcLidQt)~jrlwl%3Ta-5%3>OnnC+GL9X$15 zi};_;0JUvnfQ)Fsf3spS9q!Vgnla`g#F489M_sqBGw$HE|L$a3I2%%D)dx^&|PkWQT1+*ALiTy|w3Es%H|6 zqSjFay?996XVsL@0dp`A_aqENR3b||pvyx8q*g#f7~=YnxLqqkczLSUi=Xq+FIob; zbLfn3-il@rE(004D}TCqY5-(8{SO}UIT7;~_=B7LNhDzIsTL64=2K~DM+>p#t zQ|Ya0`{{;9u@j5mQzHSyZxfG6>&gV`^-*05$)M5aL(M$uWb6D)O!6%S1n{K_&W<@* z(MQPD)wLv;Fcq;JN=KgwBRn8vsymD!P0Fk+rcdHG7KC={G%EsjT^%J^^uEA#PH%zD zN`Q~RNE!(YFWJQ3`H`SSjPq99I5-{D6YBu^R1aY7=gZot2w@t)X$jYIk4^$0kFSFH zvxFQ4NQSKzuI`5K04XZqVh>KYg5yB*Aqye35yN%5tZiBEdl}%HYylKV7?Ntg8hBShUVAd~wKmXWx99LL$b`G62+*ZTFmzp}zrTDeyF%!}fxoGl*&IMm@pZ@L$fWk)u1nyho7IMrKP3j(O^7xbb@;jc>-6*&<>lpM6Ia#MZ&+GJg@(cjU0`7UX!!c>#XMkelV%MB0BRgq2X94= z54RhmK_;9L1SLe!uiwAz`ZAQeySs7b#hTXE>_x@J<-jN-#|$-uQ?Kc(s6~j34uMuu z3kz>QKSTK(4DajgZ0=8=KezPtQBzS-8NUH-*@Bg0n^m6a z1T@e}51?|)i?auu`+xi(gTPWqo+Bx8e)EOl@pwp4NeTSs?ui?}#-|hTC8gq=oSYDr z6aMUd-hgw@N4<*`loX*Jw;pFG*{%sfDA@n!StjD*8QL(&lN2mK#CvKtY)lR??VgCj3<9TD<>{8(&d zjPOXp%=p6p{fKrUxampIYyA>o$m0JqW~)t8Dq?7n{cmXMMXo%!U5EH^ionT4f=fK`BLV%a|gfz=L( zqqr|!LhkPFMm>K{csG!ae^dVdRd%IOO!*bl-7fbd9yK?IzLCrQ`8qr#W%>^e`y^udpKX z4huW_=+UEENQp66?Bx2(xI3X$9x<$nsDL2d#>l1pqc2_<28KmO+CnKyN_N|9m181nNkzCg~;&pV$z8zhM~f7>&h#+H5OS!2uPTJznEA@D-qy=Gd14I&qd z4<4*$udx@3ji(TH*ZVHi_gtu-$uvNtdxnQoAfp-oV`Ej5ajXGm1wiI$^jONMYre$G z^pu%!w}wW7yjBA@+_haZu+42cRpDRnrjt$u#h+pE9l2Ak<5gRCz zO5;;gQx`Hf#nU3gJN%8}3olz@q3*1S!{KKBSd1>;9~~8S_d6;Pd&1 zX%VX4At9OKTgMd#;GBLrtH!!dKdskJ`s>lqU3dN^W6XWCKb!9p3>OuRSA+wQ*ZSfFca1*_o8&S4l z$@U}cotT?D7@^yzY2yVWgbgHIlMPMG&K{q&X3Hixc&B4TqDq#?=Rs^iU|^tHdwYAI zwPC}iqo072^=tGJ6eF4VJTJmtab|6;DMXu)MR2mvfo=M640SCn*5G?QJySCp%~~yO zQK2LQ8Bk(lo1yT(2hjlwa(G@Q>x8o64?rI^+C=i)wmX=ZMo{NeZYRQHD9 zWPqt+Mnxx>s--EWhXPg$%|dMeZ)s3GR?QM&dV702z!2&Hv#%`0w4ym?T?H7K#$aIO zu$7sRfLzUo_g>4(^WSW&tD}SG>ZW&s>oM9CaT0`;vW0~Od`2nH^zMd_CFfnO(ZPcn z&}&~J5HK(pj1mfklJxguD3@K&!vI%S*pk6PEQl4duWvbk`Xre5du+N|0kE?Ex#WxA zP;vcn{TpJ~`E2(CNAY;Ft7{%BAV4c8CkKtiQY+83dO`tPMW5lT9;A%=TsiIKTb~sJ zb8}ZEeKMO}$4g5qs5@ES27|}<7DRe5nZ-&M84QeIymp^n~4SRs~NzbYBhr z43bbDGYgB0onS3uC#R+$bxYmY$azk3FVVE&y|NgylM4j;l=(-Y@L%=L|E5>@OH}@Y zSSs04+qn~MYPu^SAwfq^j}Wp2^AAG;mR3s3$Z$BLuOXQnN7#|y8~}03fzmX~-@gq^ zdcU#Tz*>-K1d>b^kZXpfpnu!!+XWrZ=($hB!^4Y;iV$}=E6NHA z3Z+Lfc`VvJ2+(;nj~6HcOiYAuf3vn$TvMYC@!1LFQbhm0^hi29C)Y{&RFJd6_V$VK z@%VGxjqO}6mwtmx=Ch)9exe~EI5;>U5F`?b6&#$~xEEd0*(ukCSp)(>t_hNplTG)g zzXM3}!sm_4b(24toO%iLhlE6>Qj3OUKx0>~UflsQGcT!abkyVfZUeO2ZjS0ro>YIS zb;}x9oE;VhdQPp-DJc=9jy5q-2lY?CVN2#4MQ!^RPkI85-T;Kbi3<~_+m`-g*09Y1 z9Zqb%Q*?B6>|qf!8TMrUH-BrN5Tw?>Y1RLK?VfBQ-^U0R)b1Y}M8MCU;zX{t@w)UU DySU|> diff --git a/docs/images/routine.png b/docs/images/routine.png deleted file mode 100644 index 74242758134eda2851ae2f3b7a4e77bcb4400b3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34057 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 diff --git a/docs/images/simple_program_csf_residuals.png b/docs/images/simple_program_csf_residuals.png deleted file mode 100644 index 0659e559050f55fbcfab5128663ab8ac24917eb7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51426 zcmd4&Wmr^w*ggucDPZW7#*yxnQer?lq*G#~rDNzCLb?PA1qBJ|Qc+Sy0YO1QNohq& zq@?>@ct6j7@Au38x;FSb)>0jUr+)r84mEc-Pkv z@VJZhcK5=%-?KvnIQshC^YWAs78e#5M7dzG-Zw-<{;$u4y?mWTa;~N%0ssooR8cYx zD)`gkmd807%zdb4!~e3Xwdz<)T36cD;hHcs3V($lz4!0!DNzAihV%z<;if?ig7xdF zIrNGeA2>)-x0w2K9PXCT<&3@9u6dPN*63JED6Pz3{l_z^nemzujO@2(Yvo(h@s7Vt zCmcIBeSZFurQ%`d_)C4%G1vt&c63y8QtJ*LJPF@Ck*!;6#fUPH62!d2q>%caDFBy8 z;2UaQ@8B8#jtK0#@&9if>aQF?QrI7V=1yaiPpYislSv!i?7I7JykZXC*7V8A$rEqG zZ~C^Zgs{=z73NpImQ1wxId@Y0H;E4!3tKE57FdFp#mkw_&A?JA% zwvm4(n@ARY8O^Ny>Da<|zv6o%x07wV@6+2P__m~Ii*(Q)%tdx?H+Js3brSUYY;C7U z%B^-eU9O_N!}g=d2*#_yn8;2Fj^V!Rkkj|{Z*h0LI_LtYeF&ch{X|*?e0OZ#pLFv% zJ@i>$IM|p;X7*~Q+6-I1x&13k@8|Jaeed45ZMyT*;O7gCkq3d1@m`T9Q{b+IPI~>f zh!3LHS`TAR3VY-!IumG;vm>tFc6x9Rdf1pAPP!Q~-sZjYS$g4TvdD*ygW2T7L}b{K zMB!J3^NqI65B}rU@l&2{Wc1cps*U!Y+g3h3bj{08L&MT<`u-xCJ=+Lecv*NRnABq@ zGE4mLZX8jrC5a)!2%u(^DO}<4ANH5<2Fu!?+r3wNH)h&;27Oyt0ybw;!%z0_T{z9X z4S(AU!#9oFtc8ZX{N8em5c#5mHw|N;aeU!n*m=n=3iGk)_5!VK!y=GIw6w>W`(~cq{{!ECuPrcSXk)C?( zK@xWQ=Ix#ki(&)|xLCr(_o3h~Ih$O<-1++4hdS%FlwL#rY*Bgn^^^Gjyq(7Z(eME- zD(R2|q@||*_#{x@eTzb#Gh)nLYJ2Dw#gE_B^<(FsN6l>4L*)Ru!}*w>+nYhXH@9|& z^%g42pHg4A&%I@RGZVnf7BnBVJ4^cCUO-z2Gqmxm&xST(8Z>WaLj)pLb0d(7r(KFE z(w#@24-b14(-s#Ur^9wW1Gs$8R^)PlANfY>nlOM5o!wzO?bbVmD;$4K|5@u5E}(F6 zG`P^%%hpw{u*V1BpX=r~+#BYebE8dG1t(5MZ{@AzHOKPr#*DFlP933nY~s4W-1+{S zh3-U}Lp-4Z?)!HOtB9k;iI>jlq9H6dutY5dJkd6OpCu2cmlfgEQYUo{v19>cIb^s;yB%Ly9{IQ^dL^?uOi1B@QKlB4bLn($v>jc7mUR7@>A&+__N z+2wp3ℜ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 diff --git a/docs/images/simple_program_data.png b/docs/images/simple_program_data.png deleted file mode 100644 index f15ba399ef2264040b410cb2f90ef0c2820dc991..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17989 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

jpn7czbMY@TL(SVP{-ojNw$N& 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⩔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 Axc~qF diff --git a/docs/images/turning_point_example.png b/docs/images/turning_point_example.png deleted file mode 100644 index 34c9cc0f95f55dac014247f7ebdd58d220a39d38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22523 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 diff --git a/docs/images/turning_point_example_res.png b/docs/images/turning_point_example_res.png deleted file mode 100644 index fd2ac3727ef1f6ffe894dcc498e43fdd0a4f5e4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68252 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 z 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 diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100755 index 2119f51..0000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index b0b66d3..0000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -sphinx -sphinx_rtd_theme -numpydoc==1.1.0 diff --git a/docs/source/CHANGELOG.rst b/docs/source/CHANGELOG.rst deleted file mode 100644 index ac1a9ce..0000000 --- a/docs/source/CHANGELOG.rst +++ /dev/null @@ -1,22 +0,0 @@ -Unreleased changes are not yet included in the pip install but are pushed to the -github. - -Unrealeased -~~~~~~~~~~~ - -Version 1.1.0 -~~~~~~~~~~~~~ - -- Two bug fixes in param_plotter() -- Extension of param_plotter() function to plot data, fit and residuals - alongside the parameter space if required. -- Extension of param_plotter() to allow for highlighting of central - regions in each panel if required. -- Inclusion of some theory into the documentation - -Version 1.2.0 -~~~~~~~~~~~~~ - -- Minor bug fix in param_plotter() -- Extension of the basis_test() function to allow users to compare different - types of DCF not just MSFs. diff --git a/docs/source/best_basis.rst b/docs/source/best_basis.rst deleted file mode 100644 index 088ff58..0000000 --- a/docs/source/best_basis.rst +++ /dev/null @@ -1,45 +0,0 @@ -This function can be used to identify which of the built in DCFs -fits the data best before running joint fits. - -To use it we begin by loading in the data, - -.. code:: - - import numpy as np - - x = np.load('Data/x.npy') - y = np.load('Data/y.npy') - -and then importing the basis_test() function. - -.. code:: - - from maxsmooth.best_basis import basis_test - -To call the function we use, - -.. code:: - - basis_test(x, y, base_dir='examples/', N=np.arange(3, 16, 1)) - -The function only requires the data but we can provide it with a base directory, -fit type and range of DCF orders to test. By defualt it uses the sign navigating -algorithm and tests :math:`{N = 3 - 13}`. Here we test the range -:math:``{N = 3 - 15}``. -The resultant graph is saved in the -base directory and the example generated here is shown below. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/Basis_functions.png - :width: 400 - :align: center - -The graph shows us which basis is the optimum for solving this problem from the -built in library (that which can reach the minimum :math:``{\chi^2}``). If we -were to go to higher N we would also find that the :math:``{\chi^2}`` value -would stop decreasing in value. The value of N for which this occurs at is the -optimum DCF order. (See the ``maxsmooth`` paper for a real world application -of this concept.) - -We can also provide this function with additional arguments such as the -fit type, minimum constrained derivative, directional exploration limits -ect. (see the ``maxsmooth`` Functions section). diff --git a/docs/source/chi_dist_example.rst b/docs/source/chi_dist_example.rst deleted file mode 100644 index d2246a3..0000000 --- a/docs/source/chi_dist_example.rst +++ /dev/null @@ -1,59 +0,0 @@ -This example will show you how to generate a plot of the :math:`{\chi^2}` -distribution as a function of the discrete sign combinations on the constrained -derivatives. - -First you will need to import your data and fit this using ``maxsmooth`` as -was done in the simple example code. - -.. code:: - - import numpy as np - - x = np.load('Data/x.npy') - y = np.load('Data/y.npy') - - from maxsmooth.DCF import smooth - - N = 10 - result = smooth(x, y, N, base_dir='examples/', - data_save=True, fit_type='qp') - -Here we have used some additional keyword arguments for the 'smooth' fitting -function. 'data_save' ensures that the files containing the tested sign combinations -and the corresponding objective function evaluations exist in the base directory -which we have changed to 'base_dir='examples/''. These files are essential for -the plotting the :math:`{\chi^2}` distribution and are not saved by ``maxsmooth`` -without 'data_save=True'. We have also set the 'fit_type' to 'qp' rather than the -default 'qp-sign_flipping'. This ensures that all of the available sign -combinations are tested rather than a sampled set giving us a full picture of the -distribution when we plot it. We have used the default DCF model to fit this data. - -We can import the 'chi_plotter' like so, - -.. code:: - - from maxsmooth.chidist_plotter import chi_plotter - -and produce the fit which gets placed in the base directory with the following -code, - -.. code:: - - chi_plotter(N, base_dir='examples/', fit_type='qp') - -We pass the same 'base_dir' as before so that the plotter can find the correct output -files. We also give the function the same 'fit_type' used for the fitting which -ensures that the files can be read. - -The resultant plot is shown below and the yellow star shows the global minimum. -This can be used to determine how well -the sign sampling approach using a descent and directional exploration -can find the global minimum. If the distribution looks like noise then it is -unlikely the sign sampling algorithm will consistently find the global minimum. -Rather it will likely repeatedly return the local minima found after the descent -algorithm and you should use the 'qp' method testing all available sign combinations -in any future fits to the data with this DCF model. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/chi_distribution.png - :width: 400 - :align: center diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100755 index 79f9fc5..0000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,111 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import sys -import os -sys.path.append(os.path.abspath('../../')) - -def get_version(short=False): - with open('../../README.rst') as f: - for line in f: - if ':Version:' in line: - ver = line.split(':')[2].strip() - if short: - subver = ver.split('.') - return '%s.%s' % tuple(subver[:2]) - else: - return ver - - -# -- Project information ----------------------------------------------------- - -project = 'maxsmooth' -copyright = '2020, Harry Thomas Jones Bevins' -author = 'Harry Thomas Jones Bevins' - -# The short X.Y version -version = get_version(True) -# The full version, including alpha/beta/rc tags -release = get_version() - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages', - 'sphinx.ext.imgconverter', - 'numpydoc' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'sphinx_rtd_theme' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = [] - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'maxsmooth.tex', 'maxsmooth Documentation', - 'Harry Thomas Jones Bevins', 'manual'), -] diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100755 index 75332ea..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -Welcome to the ``maxsmooth`` documentation! -=========================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - Introduction - maxsmooth diff --git a/docs/source/intro.rst b/docs/source/intro.rst deleted file mode 100755 index 3d85661..0000000 --- a/docs/source/intro.rst +++ /dev/null @@ -1,3 +0,0 @@ -.. title:: Introduction - -.. include:: ../../README.rst diff --git a/docs/source/maxsmooth.rst b/docs/source/maxsmooth.rst deleted file mode 100755 index 7f3a087..0000000 --- a/docs/source/maxsmooth.rst +++ /dev/null @@ -1,93 +0,0 @@ -.. toctree:: - :maxdepth: 6 - -``maxsmooth`` Theory and Algorithm ----------------------------------- - -.. include:: theory.rst - -``maxsmooth`` Example Codes ---------------------------- - -This section is designed to introduce the user to the software and the form -in which it is run. It provides basic examples of data fitting with a built in -MSF model and a user defined model. - -There are also examples of functions that can be used pre-fitting and post-fitting -for various purposes including; determination of the best DCF model from the -built in library for the problem being fitted, analysis of the :math:`{\chi^2}` -distribution as a function of the discrete sign spaces and analysis of the -parameter space surrounding the optimum results. - -The data used for all of this examples is available -`here `__. - -The example codes can be found -`here `__ and -corresponding Jupyter Notebooks are provided -`here `__. - -Simple Example code -~~~~~~~~~~~~~~~~~~~ -.. include:: simple_program.rst - -Turning Points and Inflection Points -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. include:: turning_points.rst - -New Basis Example -~~~~~~~~~~~~~~~~~ - -.. include:: new_basis_example.rst - -Best Basis Example -~~~~~~~~~~~~~~~~~~ - -.. include:: best_basis.rst - -:math:`{\chi^2}` Distribution Example -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. include:: chi_dist_example.rst - -Parameter Plotter Example -~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. include:: param_plotter_example.rst - -``maxsmooth`` Functions ------------------------ - -This section details the specifics of the built in functions in ``maxsmooth`` including -the relevant keyword arguments and default parameters for all. Where keyword arguments -are essential for the functions to run this is stated. - -smooth() -~~~~~~~~ - -.. automodule:: maxsmooth.DCF - :members: smooth - -best_basis() -~~~~~~~~~~~~ - -.. automodule:: maxsmooth.best_basis - :members: basis_test - -chidist_plotter() -~~~~~~~~~~~~~~~~~ - -.. automodule:: maxsmooth.chidist_plotter - :members: chi_plotter - -parameter_plotter() -~~~~~~~~~~~~~~~~~~~ - -.. automodule:: maxsmooth.parameter_plotter - :members: param_plotter - -Change Log ----------- - -.. include:: CHANGELOG.rst diff --git a/docs/source/new_basis_example.rst b/docs/source/new_basis_example.rst deleted file mode 100644 index 8f0ca5f..0000000 --- a/docs/source/new_basis_example.rst +++ /dev/null @@ -1,169 +0,0 @@ -This example code illustrates how to define your own basis function for the -DCF model. -It implements a modified version of the built in normalized polynomial model -but the structure is the same for more elaborate models. - -As always we need to import the data, define an order :math:`{N}` -and import the function fitting routine, smooth(). - -.. code:: - - import numpy as np - from maxsmooth.DCF import smooth - - x = np.load('Data/x.npy') - y = np.load('Data/y.npy') - - N=10 - -There are several requirements needed to define a new basis function completely -for ``maxsmooth`` to be able to fit it. They are as summarized below and then -examples of each are given in more detail, - - * **args:** Additional non-standard arguments needed in the definition of the - basis. The standard arguments are the data (x and y), the order of the fit N, - the pivot point about which a model can be fit, - the derivative order :math:`{m}` and the params. While the - pivot point is not strictly needed it is a required argument for the - functions defining a new basis to help the user in their definition. - - * **basis_functions:** This function defines the basis of the DCF model, - :math:`{\phi}` where the model can be generally defined as, - - .. math:: - - y = \sum_{k = 0}^N a_k \phi_k(x) - - where :math:`{a_k}` are the fit parameters. - - * **model:** This is the function described by the equation above. - - * **derivative:** This function defines the :math:`{m^{th}}` order derivative. - - * **derivative_pre:** This function defines the prefactors, - :math:`{\mathbf{G}}` on the derivatives where ``CVXOPT``, the quadratic - programming routine used, evaluates the constraints as, - - .. math:: - - \mathbf{Ga} \leq \mathbf{h} - - where :math:`{\mathbf{a}}` is the matrix of parameters and :math:`{\mathbf{h}}` - is the matrix of constraint limits. For more details on this see the ``maxsmooth`` - paper. - - -We can begin defining our new basis function by defining the additional arguments -needed to fit the model as a list, - -.. code:: - - arguments = [x[-1]*10, y[-1]*10] - -The next step is to define the basis functions :math:`{\phi}`. This needs to be -done in a function that has the arguments *(x, y, pivot_point, N, \*args)*. 'args' -is optional but since we need them for this basis we are passing it in. - -The basis functions, :math:`{\phi}`, should be an array of dimensions len(x) -by N and consequently evaluated at each N and x data point as shown below. - -.. code:: - - def basis_functions(x, y, pivot_point, N, *args): - - phi = np.empty([len(x), N]) - for h in range(len(x)): - for i in range(N): - phi[h, i] = args[1]*(x[h]/args[0])**i - - return phi - -We can define the model that we are fitting in a function like that shown below. -This is used for evaluating :math:`{\chi^2}` and returning the optimum fitted model -once the code has finished running. It requires the arguments -*(x, y, pivot_point, N, params, \*args)* in that order and again where 'args' is optional. -'params' is the parameters of the fit, :math:`{\mathbf{a}}` which should have length -:math:`{N}`. - -The function should return the fitted estimate of y. - -.. code:: - - def model(x, y, pivot_point, N, params, *args): - - y_sum = args[1]*np.sum([ - params[i]*(x/args[0])**i - for i in range(N)], axis=0) - - return y_sum - -Next we have to define a function for the derivatives of the model which -takes arguments *(m, x, y, N, pivot_point, params, *args)* where :math:`{m}` is -the derivative order. The function should return the :math:`{m^{th}}` order -derivative evaluation and is used for checking that the constraints have been -met and returning the derivatives of the optimum fit to the user. - -.. code:: - - def derivative(m, x, y, N, pivot_point, params, *args): - - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = args[1]*np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - params[int(m)+i]*(x)**i / \ - (args[0])**(i + 1) - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - -Finally we have to define :math:`{\mathbf{G}}` which is used by ``CVXOPT`` to -build the derivatives and constrain the functions. It takes arguments -*(m, x, y, N, pivot_point, \*args)* and should return the prefactor on the -:math:`{m^{th}}` order derivative. For a more thorough definition of the -prefactor on the derivative and an explanation of how the problem is -constrained in quadratic programming see the ``maxsmooth`` paper. - -.. code:: - - def derivative_pre(m, x, y, N, pivot_point, *args): - - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = args[1]*np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - (x)**i / \ - (args[0])**(i + 1) - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - -With our functions and additional arguments defined we can pass these -to the ``maxsmooth`` smooth() function as is shown below. This overwrites the -built in DCF model but you are still able to modify the fit type i.e. testing all -available sign combinations or sampling them. - -.. code:: - - result = smooth(x, y, N, - basis_functions=basis_functions, model=model, - derivatives=derivative, der_pres=derivative_pre, args=arguments) - -The output of the fit can be accessed as before, - -.. code:: - - print('Objective Funtion Evaluations:\n', result.optimum_chi) - print('RMS:\n', result.rms) - print('Parameters:\n', result.optimum_params) - print('Fitted y:\n', result.y_fit) - print('Sign Combinations:\n', result.optimum_signs) - print('Derivatives:\n', result.derivatives) diff --git a/docs/source/param_plotter_example.rst b/docs/source/param_plotter_example.rst deleted file mode 100644 index 0401370..0000000 --- a/docs/source/param_plotter_example.rst +++ /dev/null @@ -1,84 +0,0 @@ -We can assess the parameter space around the optimum solution -found using ``maxsmooth`` with the param_plotter() function. -This can help us identify how well a problem can be solved using the -sign navigating approach employed by ``maxsmooth`` or simply -be used to identify correlations between the foreground parameters. -For more details on this see the ``maxsmooth`` paper. - -We begin by importing and fitting the data as with the chi_plotter() -function illustrated above. - -.. code:: - - import numpy as np - - x = np.load('Data/x.npy') - y = np.load('Data/y.npy') - - from maxsmooth.DCF import smooth - - N = 5 - result = smooth(x, y, N, base_dir='examples/', fit_type='qp') - -We have changed the order of the fit to 5 to illustrate that for -order :math:`{N \leq 5}` and fits with derivatives :math:`{m \geq 2}` constrained -the function will plot each region of the graph corresponding to -different sign combinations in a different colourmap. Recall that -by default the function smooth() fits a maximally smooth function (MSF) with -derivatives of order :math:`{m \geq 2}`. If the constraints are -different or the order is greater than 5 then the viable regions will have -a single colourmap. Invalid regions are plotted as black shaded colourmaps -and the contour lines are contours of :math:`{\chi^2}`. - -Specifically, invalid regions violate the condition - -.. math:: - - \pm_m \frac{\delta^m y}{\delta x^m} \leq 0 - -where :math:`{m}` represents the derivative order, :math:`{y}` is the dependent -variable and :math:`{x}` is the independent variable. Violation of the -condition means that one or more of the constrained derivatives crosses 0 in the -band of interest. For an MSF, as mentioned, :math:`{m \geq 2}` and the sign :math:`{\pm_m}` -applies to specific derivative orders. For this specific example there are -3 constrained derivatives, :math:`{m = 2, 3, 4}` and consequently 3 signs to -optimise for alongside the parameters :math:`{a_k}`. The coloured valid regions -therefore correspond to a specific combination of :math:`{\pm_m}` for the problem. -:math:`{\pm_m}` is also referred to as :math:`{\mathbf{s}}` in the theory -section and the ``maxsmooth`` paper. - -We can import the function like so, - -.. code:: - - from maxsmooth.parameter_plotter import param_plotter - -and access it using, - -.. code:: - - param_plotter(result.optimum_params, result.optimum_signs, - x, y, N, base_dir='examples/') - -The function takes in the optimum parameters and signs found after the fit -as well as the data and order of the fit. There are a number of keyword arguments -detailed in the following section and the resultant fit is shown below. The -function by default samples the parameter ranges 50% either side of the optimum -and calculates 50 samples for each parameter. In each panel the two -labelled parameters are varied while the others are maintained at their optimum -values. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/Parameter_plot.png - -We are also able to plot the data, fit and residuals alongside the parameter -plot and this can be done by setting data_plot=True. We can also highlight the -central region in each panel of the parameter space by setting center_plot=True. - -.. code:: - - param_plotter(result.optimum_params, result.optimum_signs, - x, y, N, base_dir='examples/', data_plot=True, center_plot=True) - -which gives us the graph below. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/Parameter_plot_extended.png diff --git a/docs/source/simple_program.rst b/docs/source/simple_program.rst deleted file mode 100755 index 4a2226a..0000000 --- a/docs/source/simple_program.rst +++ /dev/null @@ -1,179 +0,0 @@ -.. highlight:: python - -In order to run the ``maxsmooth`` software using the built -in DCF models for a simple fit the user can follow the simple structure detailed here. - -An important point to make is that by default ``maxsmooth`` fits a -Maximally Smooth Function or MSF to the data. An MSF, as stated in -the introduction to the documentation, is a function which has -derivatives of order :math:`{m \geq 2}` constrained so that they do not cross -0. This means that they do not have inflection points or non smooth -structure produced by higher order derivatives. More generally a DCF -follows the constraint, - -.. math: - - \frac{\delta^m y}{\delta x^m} \leq 0 ~~\mathrm{or}~~ \frac{\delta^m y}{\delta x^m} \geq 0 $ - -for every constrained order :math:`{m}`. The set of :math:`{m}` can be any set of -derivative orders as long as those derivatives exist for the function. - -This means we can use ``maxsmooth`` to produce different DCF -models. MSFs are one of two special cases of DCF and we can also -have a Completely Smooth Function (CSF) with orders :math:`{m \geq 1}` -constrained. Alternatively we can have Partially Smooth Functions -(PSF) which are much more general and can have arbitrary sets of -derivatives constrained. We illustrate how this is implemented -towards the end of this example but we begin with the default case -fitting a MSF. - -The user should begin by importing the `smooth` class from `maxsmooth.DCF`. - -.. code:: - - from maxsmooth.DCF import smooth - -The user should then import the data they wish to fit. - -.. code:: - - import numpy as np - - x = np.load('Data/x.npy') - y = np.load('Data/y.npy') + np.random.normal(0, 0.02, len(x)) - -and define the polynomial orders they wish to fit. - -.. code:: - - N = [3, 4, 5, 6, 7, 8, 9, 10, 11] - for i in range(len(N)): - `act on N[i]` - -or for example, - -.. code:: - - N = 15 - -We can also plot the data to illustrate what is happening. -Here the data is a scaled :math:`{x^{-2.5}}` power law and I have added gaussian -noise in with a standard deviation of 0.02. - -.. code:: bash - - import matplotlib.pyplot as plt - - plt.plot(x, y) - plt.xlabel('x') - plt.ylabel('y') - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/simple_program_data.png - :width: 400 - :align: center - -`smooth` can be called as is shown below. It takes the x and y data as standard -inputs as well as the order of the fit. There are a set of keyword arguments -also available that change the type of function being fitted and these are -detailed in the documentation. - -.. code:: - - result = smooth(x, y, N) - -and it's resulting attributes can be accessed by writing -:code:`result.attribute_name`. For example printing the outputs is done like -so, - -.. code:: - - print('Objective Funtion Evaluations:\n', result.optimum_chi) - print('RMS:\n', result.rms) - print('Parameters:\n', result.optimum_params) - print('Fitted y:\n', result.y_fit) - print('Sign Combinations:\n', result.optimum_signs) - print('Derivatives:\n', result.derivatives) - - plt.plot(x, y - result.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/simple_program_msf_residuals.png - :width: 400 - :align: center - -To fit the data with a CSF we can use the 'constraints' keyword -argument in smooth(). 'constraints' sets the minimum constrained -derivative for the function which for a CSF we want to be one. - -.. code:: bash - - res = smooth(x, y, N, constraints=1) - -Note in the printed results the number of constrained derivatives has -increased by 1 and the only derivative that is allowed to cross through 0 -(Zero Crossings Used?) is the the :math:`{0^{th}}` order i.e. the data. - -.. code:: bash - - plt.plot(x, y - res.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/simple_program_csf_residuals.png - :width: 400 - :align: center - -A Partially Smooth Function can have derivatives constrained via :math:`{m \geq a}` -where :math:`{a}` is -any order above 2 or it can have a set of derivatives that are allowed to cross -zero. For the first case we can once again use the 'constraints' keyword -argument. For example we can constrain derivatives with orders :math:`{\geq 3}` which will -allow the :math:`{1^{st}}` and :math:`{2^{nd}}` order derivatives to cross zero. -This is useful when our -data features an inflection point we want to model with our fit. - -.. code:: bash - - res = smooth(x, y, N, constraints=3) - - plt.plot(x, y - res.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/simple_program_psf1_residuals.png - :width: 400 - :align: center - -To allow a particular set of derivatives to cross zero we use the -'zero_crossings' keyword. In the example below we are lifting the constraints -on the :math:`{3^{rd}}`, :math:`{4^{th}}` and :math:`{5^{th}}` order derivatives -but our minimum constrained derivative is still set at the default 2. Therefore -this PSF has derivatives of order :math:`{m = [2, 6, 7, 8, 9]}` -constrained via the condition at the begining of this example code. - -.. code:: - - res = smooth(x, y, N, zero_crossings=[3, 4, 5]) - - plt.plot(x, y - res.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/simple_program_psf2_residuals.png - :width: 400 - :align: center - -While PSFs can seem like an attractive way to improve the quality of fit they -are less 'smooth' than a MSF or CSF and consequently they can introduce -additional turning points in to your residuals obscuring any signals of -intrest. diff --git a/docs/source/theory.rst b/docs/source/theory.rst deleted file mode 100644 index fca1b77..0000000 --- a/docs/source/theory.rst +++ /dev/null @@ -1,180 +0,0 @@ -This section has been adapted from section 4 of the ``maxsmooth`` paper -in order to explain how the algorithm works. What follows is a discussion of -the fitting problem and the -``maxsmooth`` algorithm. To state concisely the problem being fitted we have - -.. math:: - - &\min_{a,~s}~~\frac{1}{2}~\mathbf{a}^T~\mathbf{Q}~\mathbf{a}~+~\mathbf{q}^T~\mathbf{a}, \\ - &\mathrm{s.t.}~~\mathbf{G(s)~a} \leq \mathbf{0}. - -where :math:`{\mathbf{s}}` are the ``maxsmooth`` signs corresponding to the -signs on the derivatives. :math:`{\mathbf{G}}` is a matrix of prefactors on the derivatives, -:math:`{\mathbf{a}}` are the parameters we are optimising for and their -product gives the derivatives we are constraining with each fit. -:math:`{\mathbf{Q}}` is the dot product of the matrix of basis functions and -its transpose and :math:`\mathbf{q}` is the negative of the transposed data, -:math:`\mathbf{y}` dotted with the basis functions. For more details on this -equation see the ``maxsmooth`` paper. -A `problem' in this context is the combination of the data, order, basis -function and constraints on the DCF. - -With ``maxsmooth`` we can test all possible sign combinations on the constrained derivatives. -This is a -reliable method and, provided the problem can be solved with quadratic programming, -will always give the correct global minimum. When the problem we are interested -in is "well defined", we can develop a quicker algorithm that searches or navigates -through the discrete ``maxsmooth`` sign spaces to find the global minimum. -Each sign space is a discrete parameter space with its own global minimum. -Using quadratic programming on a fit with a specific sign combination will -find this global minimum, and we are interested in finding the minimum -of these global minima. - -A "well defined" problem is one in which the discrete sign spaces have large -variance in their minimum :math:`{\chi^2}` values and the sign space for the -global minimum is easily identifiable. In contrast we can have an "ill defined" -problem in which the variance in minimum :math:`{\chi^2}` across all sign -combinations is small. This concept of "well defined" and "ill defined" problems -is explored further in the following two sections. - -Well Defined Problems and Discrete Sign Space Searches -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The :math:`{\chi^2}` Distribution -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We investigate the distribution of :math:`{\chi^2}` values, shown in the figure below, -for a 10 :math:`{^{th}}` order y-log(x) space MSF fit to a :math:`{y = x^{-2.5}}` -power law plus gaussian noise. - -In the figure, a combination of all positive derivatives~(negative signs) and -all negative derivatives~(positive signs) corresponds to sign combination numbers -255 and 0 respectively. Specifically, the ``maxsmooth`` signs, :math:`{\mathbf{s}}`, -are related to the sign combination number by its :math:`{C}` bit binary representation, -here :math:`{C = (N -2)}`. In binary the sign combination numbers run from -00000000 to 11111111. Each bit represents the sign on the :math:`{m^{th}}` -order derivative with a 1 representing a negative ``maxsmooth`` sign. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/chi_dist_theory.png - :width: 400 - :align: center - -The distribution appears to be composed of smooth steps or shelves; however, -when each shelf is studied closer, we find a series of peaks and troughs. This can -be seen in the subplot of the above figure which shows the distribution in the -neighbourhood of the global minimum found in the large or `global' well. This type -of distribution with a large variance in :math:`{\chi^2}` is characteristic of a "well defined" -problem. We use this example :math:`{\chi^2}` distribution to motivate the ``maxsmooth`` -algorithm outlined in the following section. - -The ``maxsmooth`` Sign Navigating Algorithm -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Exploration of the discrete sign spaces for high :math:`{N}` can be achieved by -exploring the spaces around an iteratively updated optimum sign combination. -The ``maxsmooth`` algorithm begins with a randomly generated set of signs for -which the objective function is evaluated and the optimum parameters are found. -We flip each individual sign one at a time beginning with the lowest order -constrained derivative first. When the objective function is evaluated to be lower -than that for the optimum sign combination, we replace it with the new set and repeat -the process in a `cascading' routine until the objective function stops decreasing in value. - -The local minima shown in the :math:`{\chi^2}` distribution above mean that the -cascading algorithm is not sufficient to consistently find the global minimum. -We can demonstrate this by performing 100 separate runs of the cascading -algorithm on :math:`{y = x^{-2.5} + \mathrm{noise}}`, and we use a y-log(x) space -:math:`{10^{th}}` order MSF again. We find the true global minimum 79 -times and a second local minimum 21 times. - -To prevent the routine terminating in a local minimum we perform a complete search -of the sign spaces surrounding the minimum found after the cascading routine. -We refer to this search as a directional exploration and impose limits on its -extent. In each direction we limit the number of sign combinations to explore and -we limit the maximum allowed increase in :math:`{\chi^2}` value. These limits can -be modified by the user. We prevent repeated calculations of the minimum for given -signs and treat the minimum of all tested signs as the global minimum. - -We run the consistency test again, with the full ``maxsmooth`` algorithm, and find -that for all 100 trial fits we find the same :math:`{\chi^2}` found when testing -all sign combinations. In the figure below, the red arrows show the approximate path -taken through the discrete sign spaces against the complete distribution of :math:`{\chi^2}`. -Point (1a) shows the random starting point in the algorithm, and point (1b) shows a rejected sign -combination evaluated during the cascade from point (1a) to (2). Point (2), therefore, -corresponds to a step through the cascade. Point (3) marks the end of the cascade -and the start of the left directional exploration. Finally, point (4) shows the end -of the right directional exploration where the calculated :math:`{\chi^2}` -value exceeds the limit on the directional exploration. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/routine.png - :width: 400 - :align: center - -The global well tends to be associated with signs that are all positive, -all negative or alternating. We see this in the figure above where the minimum falls -at sign combination number 169 and number 170, characteristic of the derivatives for -a :math:`{x^{-2.5}}` power law, corresponds to alternating positive and negative -derivatives from order :math:`{m = 2}`. Standard patterns of derivative signs can be seen -for all data following approximate power laws. All positive derivatives, all negative -and alternating signs correspond to data following the approximate power laws -:math:`{y\approx x^{k}}`, :math:`{y\approx -x^{k}}`, :math:`{y\approx x^{-k}}` and -:math:`{y\approx -x^{-k}}`. - -The ``maxsmooth`` algorithm assumes that the global well is present in the :math:`{\chi^2}` -distribution and this is often the case. The use of DCFs is primarily driven by a -desire to constrain previously proposed polynomial models to foregrounds. As a result -we would expect that the data being fitted could be described by one of the four -approximate power laws highlighted above and that the global minimum will fall -around an associated sign combination. In rare cases the global well is not clearly -defined and this is described in the following subsection. - -Ill Defined Problems and their Identification -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We can illustrate an "ill defined" problem, with a small variation in -:math:`{\chi^2}` across the ``maxsmooth`` sign spaces, by adding a non-smooth signal -of interest into the foreground model, :math:`{x^{-2.5}}` and fitting this with -a 10 :math:`{^{th}}` order log(y)-log(x) space MSF. We add an additional noise of -:math:`{0.020}` to the mock data. The resultant :math:`{\chi^2}` distribution with its -global minimum is shown in the top panel of the figure below. - -The global minimum, shown as a black data point, cannot be found using the -``maxsmooth`` algorithm. The cascading algorithm may terminate in any of the -approximately equal minima and the directional exploration will then quickly -terminate because of the limits imposed. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/combined_chi.png - :width: 400 - :align: center - -If we repeat the above fit and perform it with a y-x space MSF we find that the -problem is well defined with a larger :math:`{\chi^2}` variation across sign -combinations. This is shown in the bottom panel of the above figure. The results, -when using the log(y)-log(x) space MSF, are significantly better than when using -y-x space MSF meaning it is important to be able to solve "ill defined" problems. -This can be done by testing all ``maxsmooth`` signs but knowing when this is -necessary is important if you are expecting to run multiple DCF fits to the -same data set. We can focus on diagnosing whether a DCF fit to the data is -"ill defined" because a joint fit to the same data set of a DCF and signal -of interest will also feature an "ill defined" :math:`{\chi^2}` distribution. - -We can identify an "ill defined" problem by producing the equivalent of -the above figure using ``maxsmooth`` and visually assessing the :math:`{\chi^2}` -distribution for a DCF fit. Alternatively, we can use the parameter space plots, -detailed in the ``maxsmooth`` paper and later in this documentation, -to identify whether the constraints are weak or not, and if a local minima is -returned from the sign navigating routine then the minimum in these plots -will appear off centre. - -Assessment of the first derivative of the data can also help to identify an -"ill defined" problem. For the example problem this is shown in the figure below -where the derivatives have been approximated using :math:`{\Delta y/ \Delta x}`. -Higher order derivatives of the data will have similarly complex or simplistic -structures in the respective spaces. There are many combinations of parameters -that will provide smooth fits with similar :math:`{\chi^2}` values in logarithmic -space leading to the presence of local minima. This issue will also be present -in any data set where the noise or signal of interest are of a similar magnitude -to the foreground in y - x space. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/Gradients_fits.png - :width: 400 - :align: center diff --git a/docs/source/turning_points.rst b/docs/source/turning_points.rst deleted file mode 100644 index 1b84a84..0000000 --- a/docs/source/turning_points.rst +++ /dev/null @@ -1,121 +0,0 @@ -This example will walk the user through implementing DCF fits to data sets with -turning points and inflection points. It builds on the details in the -'Simple Example Code' and uses the 'constraints' keyword argument introduced -there. The 'constraints' keyword argument is used to adjust the type of DCF that -is being fitted. Recall that by default ``maxsmooth`` implements a Maximally -Smooth Function or MSF with constraints=2 i.e. derivatives of order :math:`{m \geq 2}` -constrained so that they do not cross zero. This allows for turning points in the -DCF as illustrated below. - -We start by generating some noisy data that we know will include a turning point -and defining the order of the DCF we would like to fit. - -.. code:: bash - - import numpy as np - - x = np.linspace(-10, 10, 100) - noise = np.random.normal(0, 0.02, 100) - y = x**(2) + noise - - N = 10 - -We can go ahead and plot this data just to double check it features a turning -point. - -.. code:: bash - - import matplotlib.pyplot as plt - - plt.plot(x, y) - plt.xlabel('x', fontsize=12) - plt.ylabel('y', fontsize=12) - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/turning_point_example.png - :width: 400 - :align: center - -As already stated ``maxsmooth`` does not constrain the first derivative of the -DCF by default so we can go ahead and fit the data. - -.. code:: bash - - from maxsmooth.DCF import smooth - - res = smooth(x, y, N) - -If we than plot the resultant residuals we will see that despite the data -having a turning point present we have recovered the Gaussian noise. - -.. code:: bash - - plt.plot(x, y- res.y_fit, label='Recovered Noise') - plt.plot(x, noise, label='Actual Noise') - plt.ylabel(r'$\delta y$', fontsize=12) - plt.xlabel('x', fontsize=12) - plt.legend() - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/turning_point_example_res.png - :width: 400 - :align: center - -To illustrate what happens when there is an inflection point in the data we can -define some sinusoidal data as so. - -.. code:: bash - - x = np.linspace(1, 5, 100) - noise = np.random.normal(0, 0.02, 100) - y = np.sin(x) + noise - - N = 10 - - plt.plot(x, y) - plt.xlabel('x', fontsize=12) - plt.ylabel('y', fontsize=12) - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/inflection_point_example.png - :width: 400 - :align: center - -If we proceed to fit this with smooth() in its default settings we will get a -poor fit as by default the second derivative is constrained. We need to lift this -constraint to allow for the prominent inflection point to be modelled. We do this -by setting the keyword argument constraints=3 creating a Partially Smooth Function -or PSF. - -.. code:: bash - - res_msf = smooth(x, y, N) - res_psf = smooth(x, y, N, constraints=3) - - plt.plot(x, y, label='Data') - plt.plot(x, res_msf.y_fit, label=r'MSF fit, $m \geq 2$') - plt.plot(x, res_psf.y_fit, label=r'PSF fit, $m \geq 3$') - plt.xlabel('x', fontsize=12) - plt.ylabel('y', fontsize=12) - plt.legend() - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/inflection_point_example_fits.png - :width: 400 - :align: center - -Finally, we can plot the residuals to further see that by lifting the constraint on the -second derivative we have allowed an inflection point in the data. - -.. code:: - - plt.plot(x, y- res_psf.y_fit, label='Recovered Noise') - plt.plot(x, noise, label='Actual Noise') - plt.ylabel(r'$\delta y$', fontsize=12) - plt.xlabel('x', fontsize=12) - plt.legend() - plt.show() - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/inflection_point_example_res.png - :width: 400 - :align: center diff --git a/example_codes/best_basis_example.py b/example_codes/best_basis_example.py deleted file mode 100644 index 033772d..0000000 --- a/example_codes/best_basis_example.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -This function can be used to identify which of the built in DCFs -fits the data best before running joint fits. - -To use it we begin by loading in the data, -""" - -import numpy as np - -x = np.load('Data/x.npy') -y = np.load('Data/y.npy') - -""" -and then importing the basis_test() function. -""" - -from maxsmooth.best_basis import basis_test - -""" -To call the function we use (this will take a long time to run but -the resultant graph saved in the base_dir is the important -result(see below)), -""" - -basis_test(x, y, base_dir='examples/', N=np.arange(3, 16, 1)) - -""" -The function only requires the data but we can provide it with a base directory, -fit type and range of DCF orders to test. By defualt it uses the sign navigating -algorithm and tests :math:`{N = 3 - 13}`. Here we test the range -:math:``{N = 3 - 15}``. -The resultant graph is saved in the -base directory and the example generated here is shown below. - -The graph shows us which basis is the optimum for solving this problem from the -built in library (that which can reach the minimum :math:``{\chi^2}``). If we -were to go to higher N we would also find that the :math:``{\chi^2}`` value -would stop decreasing in value. The value of N for which this occurs at is the -optimum DCF order. (See the ``maxsmooth`` paper for a real world application -of this concept.) - -We can also provide this function with additional arguments such as the -fit type, minimum constrained derivative, directional exploration limits -ect. (see the ``maxsmooth`` Functions section). -""" diff --git a/example_codes/chi_dist_example.py b/example_codes/chi_dist_example.py deleted file mode 100644 index 5b5cf06..0000000 --- a/example_codes/chi_dist_example.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -This example will show you how to generate a plot of the :math:`{\chi^2}` -distribution as a function of the descrete sign combinations on the constrained -derivatives. - -First you will need to import your data and fit this using ``maxsmooth`` as -was done in the simple example code. - -""" - -import numpy as np - -x = np.load('Data/x.npy') -y = np.load('Data/y.npy') - -from maxsmooth.DCF import smooth - -N = 10 -result = smooth(x, y, N, base_dir='examples/', - data_save=True, fit_type='qp') - -""" -Here we have used some additional keyword arguments for the 'smooth' fitting -function. 'data_save' ensures that the files containing the tested sign combinations -and the corresponding objective function evaluations exist in the base directory -which we have changed to 'base_dir='examples/''. These files are essential for -the plotting the :math:`{\chi^2}` distribution and are not saved by ``maxsmooth`` -without 'data_save=True'. We have also set the 'fit_type' to 'qp' rather than the -default 'qp-sign_flipping'. This ensures that all of the available sign -combinations are tested rather than a sampled set giving us a full picture of the -distribution when we plot it. We have used the default DCF model to fit this data. - -We can import the 'chi_plotter' like so, -""" - -from maxsmooth.chidist_plotter import chi_plotter - -""" -and produce the fit which gets placed in the base directory with the following -code, -""" - -chi_plotter(N, base_dir='examples/', fit_type='qp') - -""" -We pass the same 'base_dir' as before so that the plotter can find the correct output -files. We also give the function the same 'fit_type' used for the fitting which -ensures that the files can be read. -""" diff --git a/example_codes/new_basis_program.py b/example_codes/new_basis_program.py deleted file mode 100755 index 24f0952..0000000 --- a/example_codes/new_basis_program.py +++ /dev/null @@ -1,168 +0,0 @@ -""" -This example code illustrates how to define your own basis function for the -DCF model. -It implements a modified version of the built in normalised polynomial model -but the structure is the same for more elaborate models. - -As always we need to import the data, define an order :math:`{N}` -and import the function fitting routine, smooth(). -""" - -import numpy as np -from maxsmooth.DCF import smooth - -x = np.load('Data/x.npy') -y = np.load('Data/y.npy') - -N=10 - -""" -There are several requirements needed to define a new basis function completely -for ``maxsmooth`` to be able to fit it. They are as summarised below and then -examples of each are given in more detail, - - * **args:** Additional non-standard arguments needed in the definition of the - basis. The standard arguments are the data (x and y), the order of the fit N, - the pivot point about which a model can be fit, - the derivative order :math:`{m}` and the params. While the - pivot point is not strictly needed it is a required argument for the - functions defining a new basis to help the user in their definition. - - * **basis_functions:** This function defines the basis of the DCF model, - :math:`{\phi}` where the model can be generally defined as, - - .. math:: - - y = \sum_{k = 0}^N a_k \phi_k(x) - - where :math:`{a_k}` are the fit parameters. - - * **model:** This is the function described by the equation above. - - * **derivative:** This function defines the :math:`{m^{th}}` order derivative. - - * **derivative_pre:** This function defines the prefactors, - :math:`{\mathbf{G}}` on the derivatives where ``CVXOPT``, the quadratic - programming routine used, evaluates the constraints as, - - .. math: - - \mathbf{Ga} \leq \mathbf{h} - - where :math:`{\mathbf{a}}` is the matrix of parameters and :math:`{\mathbf{h}}` - is the matrix of constraint limits. For more details on this see the ``maxsmooth`` - paper. - - -We can begin defining our new basis function by defining the aditional arguments -needed to fit the model as a list, -""" -arguments = [x[-1]*10, y[-1]*10] - -""" -The next step is to define the basis functions :math:`{\phi}`. This needs to be -done in a function that has the arguments *(x, y, pivot_point, N, \*args)*. 'args' -is optional but since we need them for this basis we are passing it in. - -The basis functions, :math:`{\phi}`, should be an array of dimensions len(x) -by N and consequently evaluated at each N and x data point as shown below. -""" - -def basis_functions(x, y, pivot_point, N, *args): - - phi = np.empty([len(x), N]) - for h in range(len(x)): - for i in range(N): - phi[h, i] = args[1]*(x[h]/args[0])**i - - return phi - -""" -We can define the model that we are fitting in a function like that shown below. -This is used for evaluating :math:`{\chi^2}` and returning the optimum fitted model -once the code has finished running. It requires the arguments -*(x, y, pivot_point, N, params, \*args)* in that order and again where 'args' is optional. -'params' is the parameters of the fit, :math:`{\mathbf{a}}` which should have length -:math:`{N}`. - -The function should return the fitted estimate of y. -""" - -def model(x, y, pivot_point, N, params, *args): - - y_sum = args[1]*np.sum([ - params[i]*(x/args[0])**i - for i in range(N)], axis=0) - - return y_sum - -""" -Next we have to define a function for the derivatives of the model which -takes arguments *(m, x, y, N, pivot_point, params, *args)* where :math:`{m}` is -the derivative order. The function should return the :math:`{m^{th}}` order -derivative evaluation and is used for checking that the constraints have been -met and returning the derivatives of the optimum fit to the user. -""" - -def derivative(m, x, y, N, pivot_point, params, *args): - - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = args[1]*np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - params[int(m)+i]*(x)**i / \ - (args[0])**(i + 1) - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - -""" -Finally we have to define :math:`{\mathbf{G}}` which is used by ``CVXOPT`` to -build the derivatives and constrain the functions. It takes arguments -*(m, x, y, N, pivot_point, \*args)* and should return the prefactor on the -:math:`{m^{th}}` order derivative. For a more thorough definition of the -prefactor on the derivative and an explination of how the problem is -constrained in quadratic programming see the ``maxsmooth`` paper. -""" - -def derivative_pre(m, x, y, N, pivot_point, *args): - - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = args[1]*np.math.factorial(m+i) / \ - np.math.factorial(i) * \ - (x)**i / \ - (args[0])**(i + 1) - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - -""" -With our functions and additional arguments defined we can pass these -to the ``maxsmooth`` smooth() function as is shown below. This overwrites the -built in DCF model but you are still able to modify the fit type i.e. testing all -available sign combinations or sampling them. -""" - -result = smooth(x, y, N, - basis_functions=basis_functions, model=model, - derivatives=derivative, der_pres=derivative_pre, args=arguments) - -""" -The output of the fit can be accessed as before, -""" - -print('Objective Funtion Evaluations:\n', result.optimum_chi) -print('RMS:\n', result.rms) -print('Parameters:\n', result.optimum_params[2]) -print('Fitted y:\n', result.y_fit) -print('Sign Combinations:\n', result.optimum_signs) -print('Derivatives:\n', result.derivatives) diff --git a/example_codes/simple_program.py b/example_codes/simple_program.py deleted file mode 100755 index 2898c2a..0000000 --- a/example_codes/simple_program.py +++ /dev/null @@ -1,233 +0,0 @@ -""" -This section is designed to introduce the user to the software and the form -in which it is run. In order to run the `maxsmooth` software using the built -in DCFs the user can follow the simple structure detailed here. - -An important point to make is that by default ``maxsmooth`` fits a -Maximally Smooth Function or MSF to the data. An MSF, as stated in -the introduction to the documentation, is a function which has -derivatives of order :math:`{m \geq 2}` constrained so that they do not cross -0. This means that they do not have inflection points or non smooth -structure produced by higher order derivatives. More generally a DCF -follows the constraint, - -.. math: - - \frac{\delta^m y}{\delta x^m} \leq 0 ~~\mathrm{or}~~ \frac{\delta^m y}{\delta x^m} \geq 0 $ - -for every constrained order :math:`{m}`. The set of :math:`{m}` can be any set of -derivative orders as long as those derivatives exist for the function. - -This means we can use ``maxsmooth`` to produce different DCF -models. MSFs are one of two special cases of DCF and we can also -have a Completely Smooth Function (CSF) with orders :math:`{m \geq 1}` -constrained. Alternatively we can have Partially Smooth Functions -(PSF) which are much more general and can have arbitrary sets of -derivatives constrained. We illustrate how this is implemented -towards the end of this example but we begin with the default case -fitting a MSF. - -The user should begin by importing the `smooth` class from `maxsmooth.DCF`. - -.. code:: bash - from maxsmooth.DCF import smooth - -""" -from maxsmooth.DCF import smooth - -""" -The user should then import the data they wish to fit. - -.. code:: bash - - import numpy as np - - x = np.load('Data/x.npy') - y = np.load('Data/y.npy') + np.random.normal(0, 0.02, len(x)) - -and define the polynomial orders they wish to fit. - -.. code:: bash - - N = [3, 4, 5, 6, 7, 8, 9, 10, 11] - for i in range(len(N)): - `act on N[i]` - -or for example, - -.. code:: bash - - N = 15 - -We can also plot the data to illustrate what is happening. -Here the data is a scaled :math:`{x^{-2.5}}` power law and I have added gaussian -noise in with a standard deviation of 0.02. - -.. code:: bash - - import matplotlib.pyplot as plt - - plt.plot(x, y) - plt.xlabel('x') - plt.ylabel('y') - plt.show() - -""" -import numpy as np - -x = np.load('Data/x.npy') -y = np.load('Data/y.npy') + np.random.normal(0, 0.02, len(x)) - -N = 15 - -import matplotlib.pyplot as plt - -plt.plot(x, y) -plt.xlabel('x') -plt.ylabel('y') -plt.show() - -""" -`smooth` can be called as is shown below. It takes the x and y data as standard -inputs as well as the order of the fit. There are a set of keyword arguments -also available that change the type of function being fitted and these are -detailed in the documentation. - -.. code:: bash - - result = smooth(x, y, N) - -and it's resulting attributes can be accessed by writing -:code:`result.attribute_name`. For example printing the outputs is done like -so, - -.. code:: bash - - print('Objective Funtion Evaluations:\n', result.Optimum_chi) - print('RMS:\n', result.rms) - print('Parameters:\n', result.Optimum_params) - print('Fitted y:\n', result.y_fit) - print('Sign Combinations:\n', result.Optimum_signs) - print('Derivatives:\n', result.derivatives) - - plt.plot(x, y - result.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() - -""" - -result = smooth(x, y, N) - -print('Accessing Fit Attributes:') -print('Objective Funtion Evaluations:\n', result.optimum_chi) -print('RMS:\n', result.rms) -#print('Parameters:\n', result.Optimum_params) -#print('Fitted y:\n', result.y_fit) -print('Sign Combinations:\n', result.optimum_signs) -#print('Derivatives:\n', result.derivatives) - -plt.plot(x, y - result.y_fit) -plt.xlabel('x', fontsize=12) -plt.ylabel(r'$\delta y$', fontsize=12) -plt.tight_layout() -plt.show() - -""" -To fit the data with a CSF we can use the 'constraints' keyword -argument in smooth(). 'constraints' sets the minimum constrained -derivative for the function which for a CSF we want to be one. - -.. code:: bash - - res = smooth( - x, y, N, constraints=1) -""" - -res = smooth( - x, y, N, constraints=1) - -""" -Note in the printed results the number of constrained derivatives has -increased by 1 and the only derivative that is allowed to cross through 0 -(Zero Crossings Used?) is the the :math:`{0^{th}}` order i.e. the data. - -.. code:: bash - - plt.plot(x, y - res.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() -""" - -plt.plot(x, y - res.y_fit) -plt.xlabel('x', fontsize=12) -plt.ylabel(r'$\delta y$', fontsize=12) -plt.tight_layout() -plt.show() - -""" -A Partially Smooth Function can have derivatives constrained via :math:`{m \geq a}` -where :math:`{a}` is -any order above 2 or it can have a set of derivatives that are allowed to cross -zero. For the first case we can once again use the 'constraints' keyword -argument. For example we can constrain derivatives with orders :math:`{\geq 3}` which will -allow the :math:`{1^{st}}` and :math:`{2^{nd}}` order derivatives to cross zero. -This is useful when our -data features an inflection point we want to model with our fit. - -.. code:: bash - - res = smooth(x, y, N, constraints=3) - - plt.plot(x, y - res.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() - -""" - -res = smooth(x, y, N, constraints=3) - -plt.plot(x, y - res.y_fit) -plt.xlabel('x', fontsize=12) -plt.ylabel(r'$\delta y$', fontsize=12) -plt.tight_layout() -plt.show() - -""" -To allow a particular set of derivatives to cross zero we use the -'zero_crossings' keyword. In the example below we are lifting the constraints -on the :math:`{3^{rd}}`, :math:`{4^{th}}` and :math:`{5^{th}}` order derivatives -but our minimum constrained derivative is still set at the default 2. Therefore -this PSF has derivatives of order :math:`{m = [2, 6, 7, 8, 9]}` -constrained via the condition at the begining of this example code. - -.. code:: - - res = smooth(x, y, N, zero_crossings=[3, 4, 5]) - - plt.plot(x, y - res.y_fit) - plt.xlabel('x', fontsize=12) - plt.ylabel(r'$\delta y$', fontsize=12) - plt.tight_layout() - plt.show() -""" - -res = smooth(x, y, N, zero_crossings=[3, 4, 5]) - -plt.plot(x, y - res.y_fit) -plt.xlabel('x', fontsize=12) -plt.ylabel(r'$\delta y$', fontsize=12) -plt.tight_layout() -plt.show() - -""" -While PSFs can seem like an attractive way to improve the quality of fit they -are less 'smooth' than a MSF or CSF and consequently they can introduce -additional turning points in to your residuals obscuring any signals of -intrest. -""" diff --git a/example_codes/turning_points.py b/example_codes/turning_points.py deleted file mode 100644 index 4f90281..0000000 --- a/example_codes/turning_points.py +++ /dev/null @@ -1,176 +0,0 @@ -""" -This example will walk the user through implementing DCF fits to data sets with -turning points and inflection points. It builds on the details in the -'Simple Example Code' and uses the 'constraints' keyword argument introduced -there. The 'constraints' keyword argument is used to adjust the type of DCF that -is being fitted. Recall that by default ``maxsmooth`` implements a Maximally -Smooth Function or MSF with constraints=2 i.e. derivatives of order :math:`{m \geq 2}` -constrained so that they do not cross zero. This allows for turning points in the -DCF as illustrated below. - -We start by generating some noisy data that we know will include a turning point -and defining the order of the DCF we would like to fit. - -.. code:: bash - - import numpy as np - - x = np.linspace(-10, 10, 100) - noise = np.random.normal(0, 0.02, 100) - y = x**(2) + noise - - N = 10 - -""" -import numpy as np - -x = np.linspace(-10, 10, 100) -noise = np.random.normal(0, 0.02, 100) -y = x**(2) + noise - -N = 10 - -""" - -We can go ahead and plot this data just to double check it features a turning -point. - -.. code:: bash - - import matplotlib.pyplot as plt - - plt.plot(x, y) - plt.xlabel('x', fontsize=12) - plt.ylabel('y', fontsize=12) - plt.show() - -""" - -import matplotlib.pyplot as plt - -plt.plot(x, y) -plt.xlabel('x', fontsize=12) -plt.ylabel('y', fontsize=12) -plt.show() - -""" -As already stated ``maxsmooth`` does not constrain the first derivative of the -DCF by default so we can go ahead and fit the data. - -.. code:: bash - - from maxsmooth.DCF import smooth - - res = smooth(x, y, N) - -""" - -from maxsmooth.DCF import smooth - -res = smooth(x, y, N) - -""" -If we than plot the resultant residuals we will see that despite the data -having a turning point present we have recovered the Gaussian noise. - -.. code:: bash - - plt.plot(x, y- res.y_fit, label='Recovered Noise') - plt.plot(x, noise, label='Actual Noise') - plt.ylabel(r'$\delta y$', fontsize=12) - plt.xlabel('x', fontsize=12) - plt.legend() - plt.show() - -""" - -plt.plot(x, y- res.y_fit, label='Recovered Noise') -plt.plot(x, noise, label='Actual Noise') -plt.ylabel(r'$\delta y$', fontsize=12) -plt.xlabel('x', fontsize=12) -plt.legend() -plt.show() - -""" -To illustrate what happens when there is an inflection point in the data we can -define some sinusoidal data as so. - -.. code:: bash - - x = np.linspace(1, 5, 100) - noise = np.random.normal(0, 0.02, 100) - y = np.sin(x) + noise - - N = 10 - - plt.plot(x, y) - plt.xlabel('x', fontsize=12) - plt.ylabel('y', fontsize=12) - plt.show() - -""" -x = np.linspace(1, 5, 100) -noise = np.random.normal(0, 0.02, 100) -y = np.sin(x) + noise - -N = 10 - -plt.plot(x, y) -plt.xlabel('x', fontsize=12) -plt.ylabel('y', fontsize=12) -plt.show() - -""" -If we proceed to fit this with smooth() in its default settings we will get a -poor fit as by default the second derivative is constrained. We need to lift this -constraint to allow for the prominent inflection point to be modelled. We do this -by setting the keyword argument constraints=3 creating a Partially Smooth Function -or PSF. - -.. code:: bash - - res_msf = smooth(x, y, N) - res_psf = smooth(x, y, N, constraints=3) - - plt.plot(x, y, label='Data') - plt.plot(x, res_msf.y_fit, label=r'MSF fit, $m \geq 2$') - plt.plot(x, res_psf.y_fit, label=r'PSF fit, $m \geq 3$') - plt.xlabel('x', fontsize=12) - plt.ylabel('y', fontsize=12) - plt.legend() - plt.show() - -""" - -res_msf = smooth(x, y, N) -res_psf = smooth(x, y, N, constraints=3) - -plt.plot(x, y, label='Data') -plt.plot(x, res_msf.y_fit, label=r'MSF fit, $m \geq 2$') -plt.plot(x, res_psf.y_fit, label=r'PSF fit, $m \geq 3$') -plt.xlabel('x', fontsize=12) -plt.ylabel('y', fontsize=12) -plt.legend() -plt.show() - -""" -Finally, we can plot the residuals to further see that by lifting the constraint on the -second derivative we have allowed an inflection point in the data. - -.. code:: - - plt.plot(x, y- res_psf.y_fit, label='Recovered Noise') - plt.plot(x, noise, label='Actual Noise') - plt.ylabel(r'$\delta y$', fontsize=12) - plt.xlabel('x', fontsize=12) - plt.legend() - plt.show() - -""" - -plt.plot(x, y - res_psf.y_fit, label='Recovered Noise') -plt.plot(x, noise, label='Actual Noise') -plt.ylabel(r'$\delta y$', fontsize=12) -plt.xlabel('x', fontsize=12) -plt.legend() -plt.show() diff --git a/example_notebooks/Data/x.npy b/example_notebooks/Data/x.npy deleted file mode 100755 index 8e1e3924f227d9142db6e33f862b417ff445cba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 928 zcmbW0`Abw$6vwSF%NC`D5;G^UM$Jky#7g8FWw^~a`#$sDn;ezWG!;WL#SB9evou;v zG%IPrtU!t=QZOp9P0UcURobJXg(#BFo%!Rn7$cTvW&~VvK*?*U} zhr1FH?z#DIQh6dw-UGi6PE5jXpSWMoE0SxDv%)C@~gO`zoeZ3124TlZx2&&Zqb4Qu)29D)cUC z%(|4Q;`ggn__>q}^s2bdG&O=Eb21WA)LgGd4Q2FDTK!!$*PW?B@mdm8YPkMB4cgEy zgg(&lKE7J?$Ir7DsI|yU=o|4npv8Dnx#dQ`77Yp#nyo_^v#ryiOVcvg(V&AtPxVNL zk46G8SC3tm8=4k_9`o%5591H%abBQ7AM3G!jWOSV;k0^1wAp~%3~F%1fXNKsumQ)i zF5Ow;Z^TNn-)A-A_O=DLwjDFVK{E43jrd+z*>f$xgz6$1z+r+LXR`^NrKiyT%!FjJ zsgarSqJkD6nz5ZeZ#r(qj4HbD(u@;(33QMJs~O%+7Tm8pd^zf*1un8PG-kn{gA+ST z7hAEPj)T*!kQ3%RZB|@wS`?Y{#tJQsJ14}3cdaCpX+s&c70%c&m#z7|4d>2Mh1s!= zaH_W0@wkHmaL$fw8msZ69g~>RWeyx6`PbPFtYB+D@4(G#)ZnuNR>C&8LcrH^_Rd> z7#J&YzBUOgojoNI=iDTLjkEc>#CeZOaK~_5;@lTH!BXBC=j8kaC)oNdWlp|_W+&Xg IMVAx*0O&4yg#Z8m diff --git a/example_notebooks/Data/y.npy b/example_notebooks/Data/y.npy deleted file mode 100755 index b648c7ccd01868de350bc22ce53a50811116eccc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 928 zcmbWraZ?fo0Eb~&O|5iV-E}mbBG!E^C=x#l^`+ftL;GMAtw-c4Ixc(T>B?sV-d?EUY3+KwE{$~i&sk@!?m z3R$88AtjMSNn#(M&`1a1#>O?PrF`k0ras0k)m_Rb}!vjOq@k(4uNmD)r{XtRl(ohZo-}W z^vug!lCL*=Jn6ySM?#az*1Un+|J>XB_$`TJ+9R zdI)qa0w07*f6~`O9(3QI`-cV(!V+S;(=?dL`yq2juNu))n-P=WZnP3>vBwq94Zo~}DI||>{XmIF;)`>S zZ8eaEzRj3(Rio8D#=J+YMuKY9BFa->C30FOv44h2nzFF{c@-$eUzAOmRXCVzVuxRr z2D_I^5MBRWz^o}q4o}EZ83_6)0y_Rh>kMY8PV3A zfo0%LXZKjtrJx@QQeN69!G-P1WdG_Cs12qYS2wuW@z;?$xtfau!RsTr0bDpVVdIhK ziy;?Pph!jFp37nM^K@sI;??6w$|go9Hb<}8M6=fL?Ir6;bJ Gjeh}D^pM~H diff --git a/example_notebooks/best_basis_example.ipynb b/example_notebooks/best_basis_example.ipynb deleted file mode 100644 index 6dec7fb..0000000 --- a/example_notebooks/best_basis_example.ipynb +++ /dev/null @@ -1,1512 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Best Basis Function Example\n", - "\n", - "This function can be used to identify which of the built in DCFs\n", - "fits the data best before running joint fits.\n", - "\n", - "To use it we begin by loading in the data," - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "x = np.load('Data/x.npy')\n", - "y = np.load('Data/y.npy')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and then importing the basis_test() function." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from maxsmooth.best_basis import basis_test" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To call the function we use (this will take a long time to run but the resultant graph saved in the base_dir is the important result(see below))," - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.03592109680175781\n", - "Polynomial Order: 3\n", - "Number of Constrained Derivatives: 1\n", - "Signs : [-1]\n", - "Objective Function Value: 1497655.9820663128\n", - "Parameters: [[ 6.10582544e+03 -9.31235111e+01 3.66394611e-01]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.0417943000793457\n", - "Polynomial Order: 4\n", - "Number of Constrained Derivatives: 2\n", - "Signs : [-1 1]\n", - "Objective Function Value: 630224.6415792715\n", - "Parameters: [[ 8.38821635e+03 -1.68289622e+02 1.14247268e+00 -2.53882819e-03]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.1751255989074707\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 1 -1]\n", - "Objective Function Value: 211039.40071597954\n", - "Parameters: [[ 1.16900137e+04 -2.99708886e+02 2.97634623e+00 -1.32282055e-02\n", - " 2.20470092e-05]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.2592034339904785\n", - "Polynomial Order: 6\n", - "Number of Constrained Derivatives: 4\n", - "Signs : [-1 1 -1 1]\n", - "Objective Function Value: 47901.207481682766\n", - "Parameters: [[ 1.65445670e+04 -5.25932298e+02 6.94621286e+00 -4.63081000e-02\n", - " 1.54360381e-04 -2.05813906e-07]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.6042420864105225\n", - "Polynomial Order: 7\n", - "Number of Constrained Derivatives: 5\n", - "Signs : [-1 1 -1 1 -1]\n", - "Objective Function Value: 13609.251008807014\n", - "Parameters: [[ 2.20332485e+04 -8.28924147e+02 1.35734950e+01 -1.20252438e-01\n", - " 6.01262685e-04 -1.60336853e-06 1.78152216e-09]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.6632649898529053\n", - "Polynomial Order: 8\n", - "Number of Constrained Derivatives: 6\n", - "Signs : [-1 1 -1 1 -1 1]\n", - "Objective Function Value: 2900.7373462253577\n", - "Parameters: [[ 2.91306119e+04 -1.27413327e+03 2.50059677e+01 -2.76870964e-01\n", - " 1.84592628e-03 -7.38418827e-06 1.64103760e-08 -1.56299428e-11]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.319108486175537\n", - "Polynomial Order: 9\n", - "Number of Constrained Derivatives: 7\n", - "Signs : [-1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 758.0432645753858\n", - "Parameters: [[ 3.64793808e+04 -1.80544023e+03 4.11385681e+01 -5.46361938e-01\n", - " 4.56599979e-03 -2.44589063e-05 8.18866109e-08 -1.56653779e-10\n", - " 1.31110351e-13]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.0699102878570557\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 1 -1 1 -1 1 -1 -1]\n", - "Objective Function Value: 110.66485798872728\n", - "Parameters: [[ 4.80575449e+04 -2.73313091e+03 7.30162116e+01 -1.16470058e+00\n", - " 1.20545148e-02 -8.34219495e-05 3.85032270e-07 -1.14204346e-09\n", - " 1.97519989e-12 -1.51765259e-15]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.5789389610290527\n", - "Polynomial Order: 11\n", - "Number of Constrained Derivatives: 9\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 1]\n", - "Objective Function Value: 7.393381422307085\n", - "Parameters: [[ 6.61048115e+04 -4.38869929e+03 1.39334974e+02 -2.69510151e+00\n", - " 3.46370773e-02 -3.06670194e-04 1.88684080e-06 -7.95039645e-09\n", - " 2.19369588e-11 -3.57785869e-14 2.61871132e-17]]\n", - "Method: qp-sign_flipping\n", - "Model: polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "Unable to fit with N = 12 and polynomial.\n", - "#############################################################\n", - "Unable to fit with N = 13 and polynomial.\n", - "#############################################################\n", - "Unable to fit with N = 14 and polynomial.\n", - "#############################################################\n", - "Unable to fit with N = 15 and polynomial.\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.009327888488769531\n", - "Polynomial Order: 3\n", - "Number of Constrained Derivatives: 1\n", - "Signs : [-1]\n", - "Objective Function Value: 1497655.9820663128\n", - "Parameters: [[ 12.36642292 -18.95601043 7.4959134 ]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.0300595760345459\n", - "Polynomial Order: 4\n", - "Number of Constrained Derivatives: 2\n", - "Signs : [-1 1]\n", - "Objective Function Value: 630306.4266929075\n", - "Parameters: [[ 16.98854164 -34.25487279 23.37145059 -5.21966227]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.11980867385864258\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 1 -1]\n", - "Objective Function Value: 211039.40189998347\n", - "Parameters: [[ 23.67634888 -61.00806017 60.89181689 -27.1997117 4.55618066]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.1789262294769287\n", - "Polynomial Order: 6\n", - "Number of Constrained Derivatives: 4\n", - "Signs : [-1 1 -1 1]\n", - "Objective Function Value: 47901.35857551199\n", - "Parameters: [[ 33.50848936 -107.05748708 142.10947803 -95.21813512 31.89967827\n", - " -4.2747717 ]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.24662494659423828\n", - "Polynomial Order: 7\n", - "Number of Constrained Derivatives: 5\n", - "Signs : [-1 1 -1 1 -1]\n", - "Objective Function Value: 13609.355167771822\n", - "Parameters: [[ 44.62494552 -168.73359707 277.6937056 -247.26109239 124.25494289\n", - " -33.30199816 3.71891001]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.3192000389099121\n", - "Polynomial Order: 8\n", - "Number of Constrained Derivatives: 6\n", - "Signs : [-1 1 -1 1 -1 1]\n", - "Objective Function Value: 2903.3198075710584\n", - "Parameters: [[ 58.98546017 -259.27232927 511.36748101 -569.00750534 381.2492113\n", - " -153.26861131 34.23145903 -3.27658333]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.5624468326568604\n", - "Polynomial Order: 9\n", - "Number of Constrained Derivatives: 7\n", - "Signs : [-1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 809.693959133224\n", - "Parameters: [[ 73.30225501 -363.25231163 828.53418495 -1101.26443095\n", - " 920.97552878 -493.66766067 165.3869673 -31.66138003\n", - " 2.65177368]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.6008212566375732\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 1 -1 1 -1 1 -1 1]\n", - "Objective Function Value: 185.52271180814768\n", - "Parameters: [[ 91.46795521 -507.30324742 1317.98818902 -2039.73047767\n", - " 2044.78588402 -1369.43660676 611.61090642 -175.6035025\n", - " 29.41130122 -2.18936377]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.4114351272583008\n", - "Polynomial Order: 11\n", - "Number of Constrained Derivatives: 9\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 47.76711940672956\n", - "Parameters: [[ 1.10433404e+02 -6.74694461e+02 1.96060962e+03 -3.45618181e+03\n", - " 4.03623060e+03 -3.24266050e+03 1.81047132e+03 -6.93183037e+02\n", - " 1.74170087e+02 -2.59331608e+01 1.73760024e+00]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.7065720558166504\n", - "Polynomial Order: 12\n", - "Number of Constrained Derivatives: 10\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 1]\n", - "Objective Function Value: 11.447228023254151\n", - "Parameters: [[ 1.31665870e+02 -8.78310689e+02 2.82091833e+03 -5.57484226e+03\n", - " 7.42493812e+03 -6.95125927e+03 4.65431693e+03 -2.22648468e+03\n", - " 7.45559866e+02 -1.66438985e+02 2.22935804e+01 -1.35732196e+00]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 3.734036445617676\n", - "Polynomial Order: 13\n", - "Number of Constrained Derivatives: 11\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 1 1]\n", - "Objective Function Value: 11.444112769545562\n", - "Parameters: [[ 1.31670056e+02 -8.78235592e+02 2.82006690e+03 -5.57126086e+03\n", - " 7.41642436e+03 -6.93819598e+03 4.64057945e+03 -2.21631806e+03\n", - " 7.40244334e+02 -1.64510032e+02 2.18301067e+01 -1.29088543e+00\n", - " -4.30795984e-03]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 4.387500286102295\n", - "Polynomial Order: 14\n", - "Number of Constrained Derivatives: 12\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 1 -1 -1]\n", - "Objective Function Value: 11.306401917997064\n", - "Parameters: [[ 1.31886176e+02 -8.80399438e+02 2.82969289e+03 -5.59647987e+03\n", - " 7.45988774e+03 -6.99026897e+03 4.68517988e+03 -2.24389363e+03\n", - " 7.52468646e+02 -1.68292222e+02 2.25991379e+01 -1.38038730e+00\n", - " -6.33485842e-04 1.64143756e-04]]\n", - "Method: qp-sign_flipping\n", - "Model: normalised_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "Unable to fit with N = 15 and normalised_polynomial.\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.013198614120483398\n", - "Polynomial Order: 3\n", - "Number of Constrained Derivatives: 1\n", - "Signs : [-1]\n", - "Objective Function Value: 262026.00445670684\n", - "Parameters: [[ 453.94789325 -3304.94760396 12848.48072557]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.03512096405029297\n", - "Polynomial Order: 4\n", - "Number of Constrained Derivatives: 2\n", - "Signs : [-1 1]\n", - "Objective Function Value: 20748.38577973272\n", - "Parameters: [[ 479.80346345 -2805.11166824 9869.35270721 -18917.2855155 ]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.09961462020874023\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 1 -1]\n", - "Objective Function Value: 587.9790178918192\n", - "Parameters: [[ 493.93218499 -2795.75641106 8052.98018567 -18377.67801161\n", - " 26418.68826622]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.24476146697998047\n", - "Polynomial Order: 6\n", - "Number of Constrained Derivatives: 4\n", - "Signs : [-1 1 -1 1]\n", - "Objective Function Value: 11.028501878393179\n", - "Parameters: [[ 494.06573938 -2844.80441354 8092.4182417 -15433.61338446\n", - " 25979.08832504 -29830.77776964]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.2329564094543457\n", - "Polynomial Order: 7\n", - "Number of Constrained Derivatives: 5\n", - "Signs : [-1 1 -1 1 -1]\n", - "Objective Function Value: 0.89536054363089\n", - "Parameters: [[ 493.80154836 -2844.28156168 8166.45601207 -15486.90142631\n", - " 23131.20524579 -30571.97932195 19721.62457774]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.560697078704834\n", - "Polynomial Order: 8\n", - "Number of Constrained Derivatives: 6\n", - "Signs : [-1 1 -1 1 -1 -1]\n", - "Objective Function Value: 0.9406631923547155\n", - "Parameters: [[ 493.80023085 -2844.34963757 8166.99878245 -15472.00785243\n", - " 23124.44852986 -31080.54700831 18878.50472739 1147.79642835]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.0979912281036377\n", - "Polynomial Order: 9\n", - "Number of Constrained Derivatives: 7\n", - "Signs : [-1 1 -1 1 -1 -1 1]\n", - "Objective Function Value: 0.40074503248872084\n", - "Parameters: [[ 493.73147909 -2843.98620783 8186.49710985 -15478.81636806\n", - " 22406.49923193 -31992.90214159 21526.38394887 979.17792012\n", - " -124.11814625]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.904883861541748\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 1 -1 1 -1 1 1 1]\n", - "Objective Function Value: 0.11696819370957201\n", - "Parameters: [[ 4.93727942e+02 -2.84305353e+03 8.18748736e+03 -1.55936628e+04\n", - " 2.22192752e+04 -2.90869629e+04 2.86921055e+04 -1.43285866e+03\n", - " -1.62422320e+02 -1.71812810e+01]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.0069191455841064\n", - "Polynomial Order: 11\n", - "Number of Constrained Derivatives: 9\n", - "Signs : [-1 1 -1 1 -1 1 -1 -1 1]\n", - "Objective Function Value: 0.04254069968463619\n", - "Parameters: [[ 4.93730270e+02 -2.84262833e+03 8.18634589e+03 -1.56466747e+04\n", - " 2.22340146e+04 -2.76210614e+04 3.02713341e+04 -6.44160832e+03\n", - " 2.76020635e+02 2.90907510e+01 -2.91912817e+00]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.904545783996582\n", - "Polynomial Order: 12\n", - "Number of Constrained Derivatives: 10\n", - "Signs : [-1 1 -1 1 -1 -1 -1 -1 1 1]\n", - "Objective Function Value: 0.1475139705449417\n", - "Parameters: [[ 4.93726414e+02 -2.84317750e+03 8.18805379e+03 -1.55773958e+04\n", - " 2.22078641e+04 -2.95572415e+04 2.81824224e+04 1.82379274e+02\n", - " 1.08308532e+02 2.36440277e+01 -2.36075430e+00 -2.06538597e-01]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 8.326946020126343\n", - "Polynomial Order: 13\n", - "Number of Constrained Derivatives: 11\n", - "Signs : [-1 1 -1 1 -1 -1 1 1 1 1 -1]\n", - "Objective Function Value: 0.14565940838527172\n", - "Parameters: [[ 4.93726433e+02 -2.84316906e+03 8.18804865e+03 -1.55784804e+04\n", - " 2.22066486e+04 -2.95272306e+04 2.82509030e+04 1.04044343e+02\n", - " -5.67972646e+01 -1.64494837e+01 -2.21997909e+00 -1.91311147e-01\n", - " 1.60193547e-02]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 10.218279600143433\n", - "Polynomial Order: 14\n", - "Number of Constrained Derivatives: 12\n", - "Signs : [-1 1 -1 1 -1 -1 -1 -1 -1 -1 -1 -1]\n", - "Objective Function Value: 0.1435267077058029\n", - "Parameters: [[ 4.93726509e+02 -2.84316083e+03 8.18801509e+03 -1.55795097e+04\n", - " 2.22075817e+04 -2.94984276e+04 2.82708985e+04 2.83685456e-06\n", - " 5.98531490e-06 1.04120998e-05 1.33300887e-05 1.17140643e-05\n", - " 6.31795645e-06 1.57945090e-06]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 21.247979164123535\n", - "Polynomial Order: 15\n", - "Number of Constrained Derivatives: 13\n", - "Signs : [-1 1 -1 1 -1 -1 1 -1 1 -1 1 -1 1]\n", - "Objective Function Value: 0.1435267076082476\n", - "Parameters: [[ 4.93726509e+02 -2.84316083e+03 8.18801509e+03 -1.55795097e+04\n", - " 2.22075817e+04 -2.94984276e+04 2.82708985e+04 1.51859740e-07\n", - " -4.08281683e-07 1.22320235e-06 -3.13468739e-06 6.06576535e-06\n", - " -8.12554140e-06 6.68259104e-06 -2.53948471e-06]]\n", - "Method: qp-sign_flipping\n", - "Model: log_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.010521650314331055\n", - "Polynomial Order: 3\n", - "Number of Constrained Derivatives: 1\n", - "Signs : [1]\n", - "Objective Function Value: 0.00020869518403223415\n", - "Parameters: [[ 7.37478779 -2.16653462 -0.08532772]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.0279848575592041\n", - "Polynomial Order: 4\n", - "Number of Constrained Derivatives: 2\n", - "Signs : [-1 -1]\n", - "Objective Function Value: 7.945962178249629e-05\n", - "Parameters: [[ 7.65919825 -2.33438787 -0.13846147 0.03268283]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.0577082633972168\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 -1 -1]\n", - "Objective Function Value: 2.9519589230167703e-05\n", - "Parameters: [[ 8.1053049 -3.37301465 0.73354588 -0.28265339 0.04163454]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.1259753704071045\n", - "Polynomial Order: 6\n", - "Number of Constrained Derivatives: 4\n", - "Signs : [-1 1 -1 1]\n", - "Objective Function Value: 4.7866686530078086e-05\n", - "Parameters: [[ 11.97420861 -12.17151273 8.79231969 -4.01638997 0.92111621\n", - " -0.08465043]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.19004392623901367\n", - "Polynomial Order: 7\n", - "Number of Constrained Derivatives: 5\n", - "Signs : [ 1 1 1 -1 1]\n", - "Objective Function Value: 1.6199486746273087e-05\n", - "Parameters: [[ 7.20425842e+00 -1.25851203e+00 -1.29710110e+00 7.07429895e-01\n", - " -2.08993686e-01 3.19345356e-02 -2.13868931e-03]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.17575573921203613\n", - "Polynomial Order: 8\n", - "Number of Constrained Derivatives: 6\n", - "Signs : [-1 -1 -1 -1 1 -1]\n", - "Objective Function Value: 2.991082688352879e-06\n", - "Parameters: [[ 7.09636858e+00 -5.38298606e-01 -2.60833141e+00 1.83164538e+00\n", - " -7.27250867e-01 1.61416203e-01 -1.86362727e-02 9.57733373e-04]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.40761327743530273\n", - "Polynomial Order: 9\n", - "Number of Constrained Derivatives: 7\n", - "Signs : [-1 -1 -1 -1 -1 -1 -1]\n", - "Objective Function Value: 2.916516148138412e-06\n", - "Parameters: [[ 7.65649928e+00 -2.41017151e+00 9.12117226e-03 -1.38044695e-01\n", - " 1.25217126e-01 -4.83460774e-02 8.88898310e-03 -9.96226129e-04\n", - " 1.27830333e-04]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.4307398796081543\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [ 1 1 1 -1 1 -1 -1 -1]\n", - "Objective Function Value: 1.2877057064021909e-06\n", - "Parameters: [[ 7.47086108e+00 -1.85778092e+00 -7.70612804e-01 5.04276938e-01\n", - " -1.93072803e-01 4.35258774e-02 -5.62976045e-03 4.83383793e-04\n", - " -6.67385637e-05 7.58001926e-06]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.0655951499938965\n", - "Polynomial Order: 11\n", - "Number of Constrained Derivatives: 9\n", - "Signs : [ 1 1 1 1 1 1 1 1 -1]\n", - "Objective Function Value: 1.22651845499378e-07\n", - "Parameters: [[ 7.66499179e+00 -2.48235449e+00 1.81251403e-01 -3.93440648e-01\n", - " 3.70220793e-01 -1.90713385e-01 5.67481709e-02 -1.01862703e-02\n", - " 1.34677822e-03 -1.51264234e-04 5.05051666e-06]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.048088788986206\n", - "Polynomial Order: 12\n", - "Number of Constrained Derivatives: 10\n", - "Signs : [ 1 -1 1 -1 1 1 -1 -1 -1 1]\n", - "Objective Function Value: 8.493867562022565e-08\n", - "Parameters: [[ 7.15806022e+00 -1.37250138e+00 -6.97182324e-01 -1.47831045e-01\n", - " 4.06514813e-01 -2.21656535e-01 5.82978574e-02 -8.21292230e-03\n", - " 8.48742170e-04 -1.23176678e-04 1.25412339e-05 -3.80576240e-07]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.382296085357666\n", - "Polynomial Order: 13\n", - "Number of Constrained Derivatives: 11\n", - "Signs : [-1 1 -1 -1 1 -1 -1 -1 -1 -1 -1]\n", - "Objective Function Value: 3.055324946151109e-08\n", - "Parameters: [[ 7.68301809e+00 -2.42129733e+00 -1.21920620e-01 8.87258608e-02\n", - " -3.34399386e-02 6.34430704e-03 -6.34173320e-04 1.16288529e-04\n", - " -1.87369472e-05 -4.83937608e-06 1.61605413e-06 -1.47912020e-07\n", - " 1.28395199e-08]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.7251393795013428\n", - "Polynomial Order: 14\n", - "Number of Constrained Derivatives: 12\n", - "Signs : [-1 1 1 -1 -1 1 1 1 -1 -1 -1 -1]\n", - "Objective Function Value: 5.052210796660854e-09\n", - "Parameters: [[ 7.70249307e+00 -2.51259896e+00 2.59066033e-02 -3.20493055e-02\n", - " 2.47887894e-02 -1.25645968e-02 4.15038782e-03 -7.67885898e-04\n", - " 1.33219021e-05 2.76349336e-05 -5.86505921e-06 5.71531717e-07\n", - " -5.14761554e-08 4.14750450e-09]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 7.8902459144592285\n", - "Polynomial Order: 15\n", - "Number of Constrained Derivatives: 13\n", - "Signs : [ 1 1 1 1 1 1 1 -1 1 1 1 1 1]\n", - "Objective Function Value: 3.9988211853475377e-10\n", - "Parameters: [[ 7.58636610e+00 -1.95062337e+00 -1.17750057e+00 1.44976795e+00\n", - " -1.12449659e+00 5.65617501e-01 -1.82219282e-01 3.53990174e-02\n", - " -3.54739168e-03 1.05465960e-04 2.96900506e-06 1.38590451e-07\n", - " -9.43923255e-08 7.60301203e-09 -5.70637108e-10]]\n", - "Method: qp-sign_flipping\n", - "Model: loglog_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.027128934860229492\n", - "Polynomial Order: 3\n", - "Number of Constrained Derivatives: 1\n", - "Signs : [-1]\n", - "Objective Function Value: 1497655.982161551\n", - "Parameters: [[ 763.36083633 -993.22266888 611.8830205 ]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.04029440879821777\n", - "Polynomial Order: 4\n", - "Number of Constrained Derivatives: 2\n", - "Signs : [-1 1]\n", - "Objective Function Value: 630224.644018191\n", - "Parameters: [[ 763.14201809 -989.77981622 635.9784479 -127.32301211]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.09873127937316895\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 1 -1]\n", - "Objective Function Value: 211039.44680535453\n", - "Parameters: [[ 762.89171918 -987.2431695 631.33445872 -221.1328652 31.62203043]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.24682950973510742\n", - "Polynomial Order: 6\n", - "Number of Constrained Derivatives: 4\n", - "Signs : [-1 1 -1 1]\n", - "Objective Function Value: 47901.37420552028\n", - "Parameters: [[ 762.65780486 -985.2412307 614.13585004 -286.76873371 73.79956068\n", - " -8.20815904]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.22072792053222656\n", - "Polynomial Order: 7\n", - "Number of Constrained Derivatives: 5\n", - "Signs : [-1 1 -1 1 -1]\n", - "Objective Function Value: 13609.35540586465\n", - "Parameters: [[ 762.41854572 -984.57593824 607.13354585 -297.9602614 104.54925968\n", - " -21.31483194 1.93965164]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.3488931655883789\n", - "Polynomial Order: 8\n", - "Number of Constrained Derivatives: 6\n", - "Signs : [-1 1 -1 1 -1 1]\n", - "Objective Function Value: 2902.5169943483393\n", - "Parameters: [[ 7.62202860e+02 -9.84364529e+02 6.06047007e+02 -2.91056878e+02\n", - " 1.24809920e+02 -3.52279535e+01 5.95267808e+00 -4.58356651e-01]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.9981844425201416\n", - "Polynomial Order: 9\n", - "Number of Constrained Derivatives: 7\n", - "Signs : [-1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 809.7014776580646\n", - "Parameters: [[ 7.62172847e+02 -9.84136933e+02 6.05895906e+02 -2.90214281e+02\n", - " 1.23706030e+02 -4.32258796e+01 1.02246841e+01 -1.47600455e+00\n", - " 9.84987472e-02]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.253005027770996\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 1 -1 1 -1 1 -1 1]\n", - "Objective Function Value: 184.60371570390348\n", - "Parameters: [[ 7.62151272e+02 -9.83971886e+02 6.05787919e+02 -2.89820202e+02\n", - " 1.21756217e+02 -4.80855392e+01 1.42165672e+01 -2.89702908e+00\n", - " 3.65135611e-01 -2.15000653e-02]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.3548920154571533\n", - "Polynomial Order: 11\n", - "Number of Constrained Derivatives: 9\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 47.76005929110385\n", - "Parameters: [[ 7.62130157e+02 -9.83944413e+02 6.05680989e+02 -2.89775487e+02\n", - " 1.21403604e+02 -4.76818815e+01 1.64710837e+01 -4.22631277e+00\n", - " 7.56892998e-01 -8.46701216e-02 4.46078295e-03]]\n", - "Method: qp-sign_flipping\n", - "Model: legendre\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "Unable to fit with N = 12 and legendre.\n", - "#############################################################\n", - "Unable to fit with N = 13 and legendre.\n", - "#############################################################\n", - "Unable to fit with N = 14 and legendre.\n", - "#############################################################\n", - "Unable to fit with N = 15 and legendre.\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.0695505142211914\n", - "Polynomial Order: 3\n", - "Number of Constrained Derivatives: 1\n", - "Signs : [-1]\n", - "Objective Function Value: 428891.93680877023\n", - "Parameters: [[ 3.4436808 -21.98172663 40.93989028]]\n", - "Method: qp-sign_flipping\n", - "Model: exponential\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.20555758476257324\n", - "Polynomial Order: 4\n", - "Number of Constrained Derivatives: 2\n", - "Signs : [-1 1]\n", - "Objective Function Value: 53253.64560572796\n", - "Parameters: [[ -1.7465104 19.99091056 -66.61150925 87.73786416]]\n", - "Method: qp-sign_flipping\n", - "Model: exponential\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.6782536506652832\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 1 -1]\n", - "Objective Function Value: 1775.362379316301\n", - "Parameters: [[ 2.60479997 -31.96386002 156.00379446 -317.45254094 264.8566373 ]]\n", - "Method: qp-sign_flipping\n", - "Model: exponential\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.456045389175415\n", - "Polynomial Order: 6\n", - "Number of Constrained Derivatives: 4\n", - "Signs : [-1 1 -1 1]\n", - "Objective Function Value: 66.83794134233632\n", - "Parameters: [[ -3.1025033 47.47378033 -273.65180112 811.34191126\n", - " -1176.70940405 716.89176045]]\n", - "Method: qp-sign_flipping\n", - "Model: exponential\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.4152514934539795\n", - "Polynomial Order: 7\n", - "Number of Constrained Derivatives: 5\n", - "Signs : [-1 1 -1 1 -1]\n", - "Objective Function Value: 2.9736970661570026\n", - "Parameters: [[ 2.73959566e+00 -4.72620629e+01 3.51586559e+02 -1.33920007e+03\n", - " 2.89206760e+03 -3.30189577e+03 1.62078163e+03]]\n", - "Method: qp-sign_flipping\n", - "Model: exponential\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unable to fit with N = 8 and exponential.\n", - "#############################################################\n", - "Unable to fit with N = 9 and exponential.\n", - "#############################################################\n", - "Unable to fit with N = 10 and exponential.\n", - "#############################################################\n", - "Unable to fit with N = 11 and exponential.\n", - "#############################################################\n", - "Unable to fit with N = 12 and exponential.\n", - "#############################################################\n", - "Unable to fit with N = 13 and exponential.\n", - "#############################################################\n", - "Unable to fit with N = 14 and exponential.\n", - "#############################################################\n", - "Unable to fit with N = 15 and exponential.\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.009341716766357422\n", - "Polynomial Order: 3\n", - "Number of Constrained Derivatives: 1\n", - "Signs : [-1]\n", - "Objective Function Value: 1497655.9820663123\n", - "Parameters: [[ 4.47491378e+02 -1.94744934e+01 3.66394611e-01]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.0363459587097168\n", - "Polynomial Order: 4\n", - "Number of Constrained Derivatives: 2\n", - "Signs : [-1 1]\n", - "Objective Function Value: 630224.6415792727\n", - "Parameters: [[ 4.37189076e+02 -1.55772024e+01 3.76977518e-01 -2.53882819e-03]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.09820365905761719\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 1 -1]\n", - "Objective Function Value: 211039.4007159821\n", - "Parameters: [[ 4.52551586e+02 -1.27670850e+01 3.24057966e-01 -4.36486241e-03\n", - " 2.20470092e-05]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.2899622917175293\n", - "Polynomial Order: 6\n", - "Number of Constrained Derivatives: 4\n", - "Signs : [-1 1 -1 1]\n", - "Objective Function Value: 47901.20745363379\n", - "Parameters: [[ 4.77573114e+02 -1.11422011e+01 2.49549184e-01 -5.04191673e-03\n", - " 5.09336964e-05 -2.05813906e-07]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.4737884998321533\n", - "Polynomial Order: 7\n", - "Number of Constrained Derivatives: 5\n", - "Signs : [-1 1 -1 1 -1]\n", - "Objective Function Value: 13607.916758044285\n", - "Parameters: [[ 4.91677255e+02 -1.13296255e+01 2.05474005e-01 -4.32009713e-03\n", - " 6.54646582e-05 -5.29078312e-07 1.78165121e-09]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.8551750183105469\n", - "Polynomial Order: 8\n", - "Number of Constrained Derivatives: 6\n", - "Signs : [-1 1 -1 1 -1 1]\n", - "Objective Function Value: 2900.709307721885\n", - "Parameters: [[ 4.97990177e+02 -1.20537193e+01 1.86573401e-01 -3.28053519e-03\n", - " 6.62909463e-05 -8.03769342e-07 5.41424050e-09 -1.56303390e-11]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.078805685043335\n", - "Polynomial Order: 9\n", - "Number of Constrained Derivatives: 7\n", - "Signs : [-1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 772.9425170829429\n", - "Parameters: [[ 4.96107972e+02 -1.23233383e+01 1.99987304e-01 -2.88274586e-03\n", - " 5.24141034e-05 -8.55021954e-07 8.71944769e-09 -5.07957333e-11\n", - " 1.29420835e-13]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.2513985633850098\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 1 -1 1 -1 1 -1 -1]\n", - "Objective Function Value: 114.35715789988733\n", - "Parameters: [[ 4.93945308e+02 -1.24015979e+01 2.14191333e-01 -2.88025094e-03\n", - " 3.92954289e-05 -7.14295143e-07 1.07936641e-08 -1.04844768e-10\n", - " 5.92294586e-13 -1.48096272e-15]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.429729700088501\n", - "Polynomial Order: 11\n", - "Number of Constrained Derivatives: 9\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 1]\n", - "Objective Function Value: 6.119688829041132\n", - "Parameters: [[ 4.93522916e+02 -1.22743729e+01 2.16147753e-01 -3.24964824e-03\n", - " 4.04428700e-05 -4.67654196e-07 7.63661430e-09 -1.31195193e-10\n", - " 1.53730044e-12 -1.03192627e-14 2.97716087e-17]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.5962612628936768\n", - "Polynomial Order: 12\n", - "Number of Constrained Derivatives: 10\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 -1]\n", - "Objective Function Value: 0.5185149451757762\n", - "Parameters: [[ 4.93749194e+02 -1.22715588e+01 2.13554583e-01 -3.23392984e-03\n", - " 4.49032230e-05 -5.26185438e-07 5.53170212e-09 -8.55052709e-11\n", - " 1.56464678e-12 -1.95516746e-14 1.34648804e-16 -3.88201795e-19]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 5.939860820770264\n", - "Polynomial Order: 13\n", - "Number of Constrained Derivatives: 11\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 -1 1]\n", - "Objective Function Value: 0.024664728941439496\n", - "Parameters: [[ 4.93753802e+02 -1.22835521e+01 2.13667592e-01 -3.17664105e-03\n", - " 4.40184810e-05 -5.95055793e-07 6.97643747e-09 -6.18842112e-11\n", - " 7.63057079e-13 -1.72076467e-14 2.62995092e-16 -2.04365609e-18\n", - " 6.35919153e-21]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 11.123537302017212\n", - "Polynomial Order: 14\n", - "Number of Constrained Derivatives: 12\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 -1 -1 1]\n", - "Objective Function Value: 0.0017622106858247515\n", - "Parameters: [[ 4.93739171e+02 -1.22820508e+01 2.13925336e-01 -3.18871280e-03\n", - " 4.33358180e-05 -5.67263587e-07 7.50752375e-09 -8.77624134e-11\n", - " 7.14746927e-13 -7.11913360e-15 1.82932845e-16 -3.20542666e-18\n", - " 2.70044794e-20 -8.85381348e-23]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 10.028169631958008\n", - "Polynomial Order: 15\n", - "Number of Constrained Derivatives: 13\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 0.00010176158680053807\n", - "Parameters: [[ 4.93741961e+02 -1.22812852e+01 2.13851335e-01 -3.19393950e-03\n", - " 4.36671579e-05 -5.58340158e-07 6.95734293e-09 -9.19852388e-11\n", - " 1.12410726e-12 -8.39375126e-15 4.93063647e-17 -1.78002845e-18\n", - " 3.93656284e-20 -3.62369116e-22 1.23144096e-24]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "basis_test(x, y, base_dir='examples/', N=np.arange(3, 16, 1))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The function only requires the data but we can provide it with a base directory,\n", - "fit type and range of DCF orders to test. By defualt it uses the sign navigating\n", - "algorithm and tests $N = 3 - 13$. Here we test the range\n", - "$N = 3 - 15$.\n", - "The resultant graph is saved in the\n", - "base directory and the example generated here is shown below." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - " \n", - " " - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import IFrame\n", - "IFrame('./examples/Basis_functions.pdf', width=500, height=350)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The graph shows us which basis is the optimum for solving this problem from the\n", - "built in library (that which can reach the minimum $\\chi^2$). If we\n", - "were to go to higher N we would also find that the $\\chi^2$ value\n", - "would stop decreasing in value. The value of $N$ for which this occurs at is the\n", - "optimum DCF order. (See the ``maxsmooth`` paper for a real world application\n", - "of this concept.)\n", - "\n", - "We can also provide this function with additional arguments such as the\n", - "fit type, minimum constrained derivative, directional exploration limits\n", - "ect. (see the ``maxsmooth`` Functions section of the documentation)." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/example_notebooks/chi_dist_example.ipynb b/example_notebooks/chi_dist_example.ipynb deleted file mode 100644 index 2faa2ff..0000000 --- a/example_notebooks/chi_dist_example.ipynb +++ /dev/null @@ -1,171 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# $\\chi^2$ Distribution Example\n", - "\n", - "This example will show you how to generate a plot of the $\\chi^2$\n", - "distribution as a function of the descrete sign combinations on the constrained derivatives.\n", - "\n", - "First you will need to import your data and fit this using ``maxsmooth`` as was done in the simple example code." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 13.362407922744751\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 1 -1 1 -1 1 -1 -1]\n", - "Objective Function Value: 114.35715789988733\n", - "Parameters: [[ 4.93945308e+02 -1.24015979e+01 2.14191333e-01 -2.88025094e-03\n", - " 3.92954289e-05 -7.14295143e-07 1.07936641e-08 -1.04844768e-10\n", - " 5.92294586e-13 -1.48096272e-15]]\n", - "Method: qp\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "\n", - "x = np.load('Data/x.npy')\n", - "y = np.load('Data/y.npy')\n", - "\n", - "from maxsmooth.DCF import smooth\n", - "\n", - "N = 10\n", - "\n", - "result = smooth(x, y, N, base_dir='examples/',\n", - " data_save=True, fit_type='qp')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here we have used some additional keyword arguments for the 'smooth' fitting function. 'data_save' ensures that the files containing the tested sign combinations and the corresponding objective function evaluations exist in the base directory which we have changed to 'base_dir='examples/''. These files are essential for the plotting the $\\chi^2$ distribution and are not saved by ``maxsmooth`` without 'data_save=True'. We have also set the 'fit_type' to 'qp' rather than the default 'qp-sign_flipping'. This ensures that all of the available sign combinations are tested rather than a sampled set giving us a full picture of the distribution when we plot it. We have used the default DCF model to fit this data.\n", - "\n", - "We can import the 'chi_plotter' like so," - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from maxsmooth.chidist_plotter import chi_plotter" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and produce the fit which gets placed in the base directory with the following code," - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chi_plotter(N, base_dir='examples/', fit_type='qp')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We pass the same 'base_dir' as before so that the plotter can find the correct output files. We also give the function the same 'fit_type' used for the fitting which ensures that the files can be read.\n", - "\n", - "The resultant plot is stored in 'base_dir' and the yellow star shows the global minimum. This can be used to determine how well\n", - "the sign sampling approach using a descent and directional exploration\n", - "can find the global minimum. If the distribution looks like noise then it is unlikely the sign sampling algorithm will consistently find the global minimum. Rather it will likely repeatedly return the local minima found after the descent algorithm and you should use the 'qp' method testing all available sign combinations in any future fits to the data with this DCF model.\n", - "\n", - "We can visualise the plot in this notebook with the code below." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - " \n", - " " - ], - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import IFrame\n", - "IFrame('./examples/chi_distribution.pdf', width=500, height=350)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/example_notebooks/new_basis_program.ipynb b/example_notebooks/new_basis_program.ipynb deleted file mode 100644 index e2676f8..0000000 --- a/example_notebooks/new_basis_program.ipynb +++ /dev/null @@ -1,280 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# New Basis Example\n", - "\n", - "This example code illustrates how to define your own basis function for the DCF model. It implements a modified version of the built in normalised polynomial model but the structure is the same for more elaborate models.\n", - "\n", - "As always we need to import the data, define an order $N$ and import the function fitting routine, smooth()." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "from maxsmooth.DCF import smooth\n", - "\n", - "x = np.load('Data/x.npy')\n", - "y = np.load('Data/y.npy')\n", - "\n", - "N = 10" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are several requirements needed to define a new basis function completely for ``maxsmooth`` to be able to fit it. They are as summarised below and then examples of each are given in more detail,\n", - "\n", - "- **args:** Additional non-standard arguments needed in the definition of the basis. The standard arguments are the data (x and y), the order of the fit N, the pivot point about which a model can be fit, the derivative order $m$ and the params. While the pivot point is not strictly needed it is a required argument for the functions defining a new basis to help the user in their definition.\n", - "\n", - "- **basis_functions:** This function defines the basis of the DCF model, $\\phi$ where the model can be generally defined as, \n", - " \n", - " $y = \\sum_{k = 0}^N a_k \\phi_k(x)$ \n", - " \n", - " where $a_k$ are the fit parameters.\n", - "\n", - "- **model:** This is the function described by the equation above.\n", - "\n", - "- **derivative:** This function defines the $m^{th}$ order derivative.\n", - "\n", - "- **derivative_pre:** This function defines the prefactors, $\\mathbf{G}$ on the derivatives where ``CVXOPT``, the quadratic programming routine used, evaluates the constraints as,\n", - "\n", - " $\\mathbf{Ga} \\leq \\mathbf{h}$\n", - " \n", - " where $\\mathbf{a}$ is the matrix of parameters and $\\mathbf{h}$ is the matrix of constraint limits. For more details on this see the ``maxsmooth``paper.\n", - "\n", - "\n", - "We can begin defining our new basis function by defining the aditional arguments needed to fit the model as a list," - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "arguments = [x[-1]*10, y[-1]*10]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next step is to define the basis functions $\\phi$. This needs to be done in a function that has the arguments *(x, y, pivot_point, N, *args)*. 'args' is optional but since we need them for this basis we are passing it in.\n", - "\n", - "The basis functions, $\\phi$, should be an array of dimensions len(x)\n", - "by N and consequently evaluated at each N and x data point as shown below." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "def basis_functions(x, y, pivot_point, N, *args):\n", - "\n", - " phi = np.empty([len(x), N])\n", - " for h in range(len(x)):\n", - " for i in range(N):\n", - " phi[h, i] = args[1]*(x[h]/args[0])**i\n", - "\n", - " return phi" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can define the model that we are fitting in a function like that shown below. This is used for evaluating $\\chi^2$ and returning the optimum fitted model once the code has finished running. It requires the arguments *(x, y, pivot_point, N, params, \\*args)* in that order and again where 'args' is optional. 'params' is the parameters of the fit, $\\mathbf{a}$ which should have length $N$.\n", - "\n", - "The function should return the fitted estimate of y." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def model(x, y, pivot_point, N, params, *args):\n", - "\n", - " y_sum = args[1]*np.sum([\n", - " params[i]*(x/args[0])**i\n", - " for i in range(N)], axis=0)\n", - "\n", - " return y_sum" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next we have to define a function for the derivatives of the model which takes arguments *(m, x, y, N, pivot_point, params, *args)* where $m$ is the derivative order. The function should return the $m^{th}$ order derivative evaluation and is used for checking that the constraints have been met and returning the derivatives of the optimum fit to the user." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "def derivative(m, x, y, N, pivot_point, params, *args):\n", - "\n", - " mth_order_derivative = []\n", - " for i in range(N):\n", - " if i <= m - 1:\n", - " mth_order_derivative.append([0]*len(x))\n", - " for i in range(N - m):\n", - " mth_order_derivative_term = args[1]*np.math.factorial(m+i) / \\\n", - " np.math.factorial(i) * \\\n", - " params[int(m)+i]*(x)**i / \\\n", - " (args[0])**(i + 1)\n", - " mth_order_derivative.append(\n", - " mth_order_derivative_term)\n", - "\n", - " return mth_order_derivative" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally we have to define $\\mathbf{G}$ which is used by ``CVXOPT`` to\n", - "build the derivatives and constrain the functions. It takes arguments\n", - "*(m, x, y, N, pivot_point, \\*args)* and should return the prefactor on the $m^{th}$ order derivative. For a more thorough definition of the\n", - "prefactor on the derivative and an explination of how the problem is\n", - "constrained in quadratic programming see the ``maxsmooth`` paper." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "def derivative_pre(m, x, y, N, pivot_point, *args):\n", - "\n", - " mth_order_derivative = []\n", - " for i in range(N):\n", - " if i <= m - 1:\n", - " mth_order_derivative.append([0]*len(x))\n", - " for i in range(N - m):\n", - " mth_order_derivative_term = args[1]*np.math.factorial(m+i) / \\\n", - " np.math.factorial(i) * \\\n", - " (x)**i / \\\n", - " (args[0])**(i + 1)\n", - " mth_order_derivative.append(\n", - " mth_order_derivative_term)\n", - "\n", - " return mth_order_derivative" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our functions and additional arguments defined we can pass these\n", - "to the ``maxsmooth`` smooth() function as is shown below. This overwrites the built in DCF model but you are still able to modify the fit type i.e. testing all available sign combinations or sampling them." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.430711507797241\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 1 -1 -1 -1 -1 1 -1]\n", - "Objective Function Value: 211043.08775526902\n", - "Parameters: [[ 6.44274707e+00 -2.47768148e+02 3.69078272e+03 -2.46050489e+04\n", - " 6.15121485e+04 -3.93622291e+00 2.73964765e+01 6.32967370e+00\n", - " -7.88321214e-01 8.20907171e-02]]\n", - "Method: qp-sign_flipping\n", - "Model: user_defined\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - } - ], - "source": [ - "result = smooth(x, y, N,\n", - " basis_functions=basis_functions, model=model,\n", - " derivatives=derivative, der_pres=derivative_pre, args=arguments)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The output of the fit can be accessed as before," - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Objective Funtion Evaluations:\n", - " 211043.08775526902\n", - "RMS:\n", - " 45.93942617787786\n", - "Sign Combinations:\n", - " [-1 1 -1 -1 -1 -1 1 -1]\n" - ] - } - ], - "source": [ - "print('Objective Funtion Evaluations:\\n', result.optimum_chi)\n", - "print('RMS:\\n', result.rms)\n", - "#print('Parameters:\\n', result.optimum_params[2])\n", - "#print('Fitted y:\\n', result.y_fit)\n", - "print('Sign Combinations:\\n', result.optimum_signs)\n", - "#print('Derivatives:\\n', result.derivatives)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/example_notebooks/param_plotter_example.ipynb b/example_notebooks/param_plotter_example.ipynb deleted file mode 100644 index ffbfb48..0000000 --- a/example_notebooks/param_plotter_example.ipynb +++ /dev/null @@ -1,260 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Parameter Plotter Example\n", - "\n", - "We can assess the parameter space around the optimum solution\n", - "found using ``maxsmooth`` with the param_plotter() function.\n", - "This can help us identify how well a problem can be solved using the\n", - "sign sampling approach employed by ``maxsmooth`` or simply\n", - "be used to identify correlations between the foreground parameters.\n", - "For more details on this see the ``maxsmooth`` paper.\n", - "\n", - "We begin by importing and fitting the data as with the chi_plotter()\n", - "function illustrated above." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 0.13113069534301758\n", - "Polynomial Order: 5\n", - "Number of Constrained Derivatives: 3\n", - "Signs : [-1 1 -1]\n", - "Objective Function Value: 211039.4007159821\n", - "Parameters: [[ 4.52551586e+02 -1.27670850e+01 3.24057966e-01 -4.36486241e-03\n", - " 2.20470092e-05]]\n", - "Method: qp\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "\n", - "x = np.load('Data/x.npy')\n", - "y = np.load('Data/y.npy')\n", - "\n", - "from maxsmooth.DCF import smooth\n", - "\n", - "N = 5\n", - "result = smooth(x, y, N, base_dir='examples/', fit_type='qp')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We have changed the order of the fit to 5 to illustrate that for\n", - "order $N \\leq 5$ and fits with derivatives $m \\geq 2$ constrained\n", - "the function will plot each region of the graph corresponding to\n", - "different sign functions in a different colourmap. If the constraints are different or the order is greater than 5 then the viable regions will have a single colourmap. Invalid regions are plotted as black shaded colourmaps and the contour lines are contours of $\\chi^2$\n", - "\n", - "Specifically, invalid regions violate the condition\n", - "\n", - " $\\pm_m \\frac{\\delta^m y}{\\delta x^m} \\leq 0$\n", - "\n", - "where $m$ represents the derivative order, $y$ is the dependent\n", - "variable and $x$ is the independent variable. Violation of the\n", - "condition means that one or more of the constrained derivatives crosses 0 in the band of interest. For an MSF, as mentioned, $m \\geq 2$ and the sign $\\pm_m$ applies to specific derivative orders. For this specific example there are 3 constrained derivatives, $m = 2, 3, 4$ and consequently 3 signs to optimise for alongside the parameters $a_k$. The coloured valid regions therefore correspond to a specific combination of $\\pm_m$ for the problem. $\\pm_m$ is also referred to as $\\mathbf{s}$ in the theory section and the ``maxsmooth`` paper.\n", - "\n", - "We can import the function like so," - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from maxsmooth.parameter_plotter import param_plotter" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and access it using," - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[########################################################################] 100%\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "param_plotter(result.optimum_params, result.optimum_signs,\n", - " x, y, N, base_dir='examples/')" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - " \n", - " " - ], - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import IFrame\n", - "IFrame('./examples/Parameter_plot.pdf', width=800, height=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The function takes in the optimum parameters and signs found after the fit as well as the data and order of the fit. There are a number of keyword arguments detailed in the following section and the resultant fit is shown below. The function by default samples the parameter ranges 50% either side of the optimum and calculates 50 spamples for each parameter. The resultant graph is saved into the base_dir and in each panel the two labelled parameters are varied while the others are maintained at their optimum values." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are also able to plot the data, fit and residuals alongside the parameter plot and this can be done by setting data_plot=True. We can also highlight the central region in each panel of the parameter space by setting center_plot=True." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[########################################################################] 100%\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "param_plotter(result.optimum_params, result.optimum_signs,\n", - " x, y, N, base_dir='examples/', data_plot=True, center_plot=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - " \n", - " " - ], - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import IFrame\n", - "IFrame('./examples/Parameter_plot.pdf', width=800, height=600)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/example_notebooks/simple_program.ipynb b/example_notebooks/simple_program.ipynb deleted file mode 100644 index 88f7ddd..0000000 --- a/example_notebooks/simple_program.ipynb +++ /dev/null @@ -1,394 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simple ``maxsmooth`` Example Code\n", - "\n", - "This section is designed to introduce the user to the software and the form in which it is run. In order to run the ``maxsmooth`` software using the built in DCFs the user can follow the simple structure detailed here.\n", - "\n", - "An important point to make is that by default ``maxsmooth`` fits a Maximally Smooth Function or MSF to the data. An MSF, as stated in the introduction to the documentation, is a function which has derivatives of order $m \\geq 2$ constrained so that they do not cross 0. This means that they do not have inflection points or non smooth structure produced by higher order derivatives. More generally a DCF follows the constraint,\n", - "\n", - "$ \\frac{\\delta^m y}{\\delta x^m} \\leq 0 ~~\\mathrm{or}~~ \\frac{\\delta^m y}{\\delta x^m} \\geq 0 $\n", - "\n", - "for every constrained order $m$. The set of $m$ can be any set of derivative orders as long as those derivatives exist for the function.\n", - "\n", - "This means we can use ``maxsmooth`` to produce different DCF models. MSFs are one of two special cases of DCF and we can also have a Completely Smooth Function (CSF) with orders $m \\geq 1$ constrained. Alternatively we can have Partially Smooth Functions (PSF) which are much more general and can have arbitrary sets of derivatives constrained. We illustrate how this is implemented towards the end of this example but we begin with the default case fitting a MSF.\n", - "\n", - "The user should begin by importing the *smooth* class from *maxsmooth.DCF*." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from maxsmooth.DCF import smooth" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The user should then import the data they wish to fit and define the order of the function they wish to fit with. We can also plot the data to illustrate what is happening. Here the 'y' data is a scaled $x^{-2.5}$ power law and I have added gaussian noise in with a standard deviation of 0.02." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "

" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "import numpy as np\n", - "\n", - "x = np.load('Data/x.npy')\n", - "y = np.load('Data/y.npy') + np.random.normal(0, 0.02, len(x))\n", - "\n", - "N = 15\n", - "\n", - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(x, y)\n", - "plt.xlabel('x')\n", - "plt.ylabel('y')\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "*smooth* can be called as is shown below. It takes the x and y data as standard inputs as well as the order of the fit. There are a set of keyword arguments also available that change the type of function being fitted and these are detailed in the documentation." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 13.211431741714478\n", - "Polynomial Order: 15\n", - "Number of Constrained Derivatives: 13\n", - "Signs : [-1 1 -1 1 -1 1 -1 1 -1 1 1 -1 -1]\n", - "Objective Function Value: 0.049767752022560015\n", - "Parameters: [[ 4.93743954e+02 -1.22808736e+01 2.13803269e-01 -3.19414523e-03\n", - " 4.38004681e-05 -5.60542296e-07 6.84052878e-09 -8.93587837e-11\n", - " 1.15739748e-12 -9.46473558e-15 4.99311590e-17 -1.61222191e-18\n", - " 3.82618421e-20 -3.68041597e-22 1.28748236e-24]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - } - ], - "source": [ - "res = smooth(x, y, N)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can access the results of the fit and plot the residuals as shown below. Here a number of the attributes are commented out but included for the sake of completness." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Accessing Fit Attributes:\n", - "Objective Funtion Evaluations:\n", - " 0.049767752022560015\n", - "RMS:\n", - " 0.0223086871022389\n", - "Sign Combinations:\n", - " [-1 1 -1 1 -1 1 -1 1 -1 1 1 -1 -1]\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "print('Accessing Fit Attributes:')\n", - "print('Objective Funtion Evaluations:\\n', res.optimum_chi)\n", - "print('RMS:\\n', res.rms)\n", - "#print('Parameters:\\n', res.optimum_params)\n", - "#print('Fitted y:\\n', res.y_fit)\n", - "print('Sign Combinations:\\n', res.optimum_signs)\n", - "#print('Derivatives:\\n', res.derivatives)\n", - "\n", - "plt.plot(x, y - res.y_fit)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.ylabel(r'$\\delta y$', fontsize=12)\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To fit the data with a CSF we can use the 'constraints' keyword argument in smooth(). 'constraints' sets the minimum constrained derivative for the function which for a CSF we want to be one." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 17.524691343307495\n", - "Polynomial Order: 15\n", - "Number of Constrained Derivatives: 14\n", - "Signs : [ 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 0.04997366530209926\n", - "Parameters: [[ 4.93743471e+02 -1.22808405e+01 2.13814758e-01 -3.19444274e-03\n", - " 4.37560407e-05 -5.59706086e-07 6.90272432e-09 -9.04292660e-11\n", - " 1.11944074e-12 -8.77169765e-15 5.93712196e-17 -1.83309620e-18\n", - " 3.79739211e-20 -3.40532152e-22 1.13892498e-24]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 1\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - } - ], - "source": [ - "res = smooth(\n", - " x, y, N, constraints=1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note in the printed results the number of constrained derivatives has increased by 1 and the only derivative that is allowed to cross through 0 (Zero Crossings Used?) is the the $0^{th}$ order i.e. the data." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(x, y - res.y_fit)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.ylabel(r'$\\delta y$', fontsize=12)\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A Partially Smooth Function can have derivatives constrained via $m \\geq a$ where $a$ is any order above 2 or it can have a set of derivatives that are allowed to cross zero. For the first case we can once again use the 'constraints' keyword argument. For example we can constrain derivatives with orders $\\geq 3$ which will allow the $1^{st}$ and $2^{nd}$ order derivatives to cross zero. This is useful when our data features an inflection point we want to model with our fit." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 11.277308464050293\n", - "Polynomial Order: 15\n", - "Number of Constrained Derivatives: 12\n", - "Signs : [ 1 -1 1 -1 1 -1 1 -1 1 1 -1 1]\n", - "Objective Function Value: 0.04967661128564428\n", - "Parameters: [[ 4.93744160e+02 -1.22808738e+01 2.13797953e-01 -3.19410879e-03\n", - " 4.38228511e-05 -5.60764306e-07 6.80628376e-09 -8.89234642e-11\n", - " 1.18037177e-12 -9.83236755e-15 4.35392184e-17 -1.47274085e-18\n", - " 3.85498374e-20 -3.87573378e-22 1.39326338e-24]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 3\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1, '2': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "res = smooth(x, y, N, constraints=3)\n", - "\n", - "plt.plot(x, y - res.y_fit)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.ylabel(r'$\\delta y$', fontsize=12)\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To allow a particular set of derivatives to cross zero we use the 'zero_crossings' keyword. In the example below we are lifting the constraints on the $3^{rd}$, $4^{th}$ and $5^{th}$ order derivatives but our minimum constrained derivative is still set at the default 2. Therefore this PSF has derivatives of order $m = [2, 6, 7, 8, 9]$ constrained via the condition at the begining of this example code." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 3.629124641418457\n", - "Polynomial Order: 15\n", - "Number of Constrained Derivatives: 10\n", - "Signs : [-1 -1 1 -1 1 -1 1 1 1 -1]\n", - "Objective Function Value: 0.049724821013759544\n", - "Parameters: [[ 4.93744054e+02 -1.22808710e+01 2.13800665e-01 -3.19414659e-03\n", - " 4.38115602e-05 -5.60616156e-07 6.82331415e-09 -8.91658318e-11\n", - " 1.16913341e-12 -9.64513657e-15 4.66060212e-17 -1.54047402e-18\n", - " 3.84176646e-20 -3.78334129e-22 1.34361764e-24]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossing Derivatives: [3, 4, 5]\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 1, '3': 1, '4': 1, '5': 1}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "res = smooth(x, y, N, zero_crossings=[3, 4, 5])\n", - "\n", - "plt.plot(x, y - res.y_fit)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.ylabel(r'$\\delta y$', fontsize=12)\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "While PSFs can seem like an attractive way to improve the quality of fit they are less 'smooth' than a MSF or CSF and consequently they can introduce additional turning points in to your residuals obscuring any signals of intrest." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/example_notebooks/turning_points.py.ipynb b/example_notebooks/turning_points.py.ipynb deleted file mode 100644 index 1d8cbc7..0000000 --- a/example_notebooks/turning_points.py.ipynb +++ /dev/null @@ -1,316 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Turning Points and Inflection Points\n", - "\n", - "This example will walk the user through implementing DCF fits to data sets with turning points and inflection points. It builds on the details in the 'Simple Example Code' and uses the 'constraints' keyword argument introduced there. The 'constraints' keyword argument is used to adjust the type of DCF that is being fitted. Recall that by default ``maxsmooth`` implements a Maximally Smooth Function or MSF with constraints=2 i.e. derivatives of order $m \\geq 2$ constrained so that they do not cross zero. This allows for turning points in the\n", - "DCF as illustrated below.\n", - "\n", - "We start by generating some noisy data that we know will include a turning point and defining the order of the DCF we would like to fit." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "x = np.linspace(-10, 10, 100)\n", - "noise = np.random.normal(0, 0.02, 100)\n", - "y = x**(2) + noise\n", - "\n", - "N = 10" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can go ahead and plot this data just to double check it features a turning point." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEJCAYAAACOr7BbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3dd3yUZb738c8vvZIQEkISEhIg9G4I3Ya6qKyoa8EKNtayR1fPrrrrOT4+6zlbdNV1dy2LFbuCurBYWFRsSEukl0AoIYVAICGE9HI9f8zgE3ECCWbmmsn83q9XXplyh/nmzpBv7nZdYoxBKaWUOl6A7QBKKaW8kxaEUkopl7QglFJKuaQFoZRSyiUtCKWUUi4F2Q7QWeLj4016errtGEop5VNyc3MPGmMSXD3XZQoiPT2dnJwc2zGUUsqniEhBW8/pLiallFIuaUEopZRySQtCKaWUS1oQSimlXNKCUEop5ZJHCkJEXhSRAyKyqdVjcSKyVER2OD93dz4uIvJXEckXkQ0iMsYTGZVSSn2fp7YgXgamHffY/cCnxphM4FPnfYDzgUznxxzgGQ9lVEop1YpHCsIY8yVQftzDM4B5ztvzgItbPf6KcVgJxIpIkruybSs9wlPL8t31zyullNsYY/jfD7awuaTSLf++zWMQicaYfc7bpUCi83YKUNhquSLnYz8gInNEJEdEcsrKyk4pxPL8Qzy6JI9tpUdO6euVUsqWlbvKee6r3WzfX+WWf98rDlIbx6xFHZ65yBgz1xiTZYzJSkhweaX4SV0yOoWQwADeXlN48oWVUsqLvL1mL9FhQZw/zD07WWwWxP5ju46cnw84Hy8GUlst19v5mFvERYZw7tBE3l9bTF1js7teRimlOlVlTSMfbirl4lEphAUHuuU1bBbEImCW8/YsYGGrx693ns00HqhstSvKLWaOTeVwTSP/3rLfnS+jlFKdZuH6YhqaWrhybOrJFz5FnjrN9U1gBTBQRIpE5Cbgj8C5IrIDOMd5H+BDYBeQDzwH3O7ufJP6xZMSG847uptJKeUDjDG8ubqQYSndGJYS47bX8chorsaYq9p4aqqLZQ1wh3sTfV9AgHBFVipPfLKdwvIaUuMiPPnySinVIZuKj7B13xEenjHUra/jFQepvcHlWb0RgXdydCtCKeXd3lqzl9CgAC4a5fIEz06jBeGUHBvO6ZkJzM8poqm5xXYcpZRyqbahmUXrSrhweBIx4cFufS0tiFZmjk2l9EgdX2w/tWsqlFLK3RZvKKGqvokr3Hhw+hgtiFbOGZJIfFQob67eazuKUkq59NaaQvomRDIuI87tr6UF0UpwYABXZPXms20H2FdZazuOUkp9T15pFbkFFVw1Ng0RcfvraUEcZ+bYNFoMvLOmyHYUpZT6njdX7yUkMICfndbbI6+nBXGctB4RTMmM5+01e2lu6fDoH0op5RZ1jc28v7aYnwzrRVxkiEdeUwvChauy0yiprONLPVitlPISH23aR2VtI1d54OD0MVoQLpwzOJH4qBDe0IPVSikv8ebqQtJ7RDC+bw+PvaYWhAshQQFcnpXKZ9sOUFpZZzuOUsrP5R84yurd5czMTiMgwP0Hp4/RgmjDzLGpNLcYvbJaKWXdm6v3Ehwo/GyMZw5OH6MF0YY+PSKZkhnPW6v1YLVSyp66xmYW5BZx3tBeJESHevS1tSBO4GrnwerP8w6cfGGllHKDDzc6Dk5fk53m8dfWgjiBc4YkkhAdyhur9GC1UsqO11ftpW98JBP6ee7g9DFaECcQHBjAlVmpLMs7QPFhvbJaKeVZ20qPOK6czvbMldPH04I4iZnZqRjgbT3lVSnlYW+s8uyV08fTgjiJ3t0jOGNAAm/nFOow4Eopj6lpaOL9b4u5YLjnrpw+nhZEO1ydncb+I/V8slUPViulPONf6x3Del89ro+1DFoQ7XD2oJ4kxYTx+qoC21GUUn7AGMMrKwoYmBjN2PTu1nJoQbRDUGAAV2en8dWOg+w+WG07jlKqi1tbeJjNJUe4dkIfKwenj9GCaKcrs1MJChBeX6lbEUop93ptRQFRoUFcMtq9c06fjBZEO/WMDuMnw3oxP7eI2oZm23GUUl1UeXUDizfs49IxKUSFBlnNogXRAdeN70NlbSP/2lBiO4pSqot6J6eQhuYWrh1v7+D0MVoQHTAuI47MnlG6m0kp5RbNLYbXVhYwvm8cAxKjbcfRgugIEeHa8X1YX1TJhqLDtuMopbqYL7YfoKiiluvGp9uOAmhBdNglY1KIDAlk3je6FaGU6lzzvimgZ3Qo5w1NtB0F0ILosG5hwVw6pjf/2lDCoaP1tuMopbqI3Qer+WJ7GdeM60NwoHf8avaOFD7m+gl9aGhq4a01OpmQUqpzvLqigOBA4apxnptz+mS0IE5BZmI0k/r34PWVBTo+k1LqR6uub2J+biHnD0uiZ3SY7Tjf0YI4RbMmpFNSWcfSLfttR1FK+bh/riumqq6JWRPtn9ramhbEKZo6OJGU2HDmrdhjO4pSyocZY3jlmwKGJndjTJq9cZdcsV4QInK3iGwWkU0i8qaIhIlIhoisEpF8EXlbROyMdXsCgQHCdRP6sHJXOdtKj9iOo5TyUSt3lZO3v4pZE9KtjrvkitWCEJEU4E4gyxgzDAgEZgJ/Ap4wxvQHKoCb7KVs25VZqYQFB/Dy8j22oyilfNS8b/YQGxHMT0cm247yA9a3IIAgIFxEgoAIYB9wNrDA+fw84GJL2U6oe2QIl4zuzXtri/WUV6VUhxUfruXfW0qZOTaN8JBA23F+wGpBGGOKgT8De3EUQyWQCxw2xjQ5FysCXA5pKCJzRCRHRHLKyso8EfkHbpyUTkNTC2/qlKRKqQ56dYXjgttrx6dZTuKa7V1M3YEZQAaQDEQC09r79caYucaYLGNMVkJCgptSnlhmYjRTMuN5ZUUBDU16yqtSqn3qGpt5a81ezhvSi97dI2zHccn2LqZzgN3GmDJjTCPwHjAJiHXucgLoDRTbCtgeN07O4EBVPR9s1FFelVLts3BdMYdrGpk9Kd12lDbZLoi9wHgRiRDH4fupwBZgGXCZc5lZwEJL+drljMwE+iVE8sLXuzHG2I6jlPJyxhheWr6HQb2iGZcRZztOm2wfg1iF42D0t8BGZ565wH3APSKSD/QAXrAWsh0CAoQbJmWwqfgIa/ZU2I6jlPJyq3aXs620itkTve/U1tZsb0FgjPk/xphBxphhxpjrjDH1xphdxphsY0x/Y8zlxhivP0Xo0jEpxIQH89Ly3bajKKW83Itf7yY2IpgZo+xOKXoy1guiq4gICeKq7DSWbC6lsLzGdhyllJfafbCapVv3c+24Pl55amtrWhCdaNbEPogI877ZYzuKUspLvfj1boIDArjey8ZdckULohMlxYRzwfAk3l5TyNH6ppN/gVLKr1RUNzA/t5CLRyd71aitbdGC6GQ3Tkqnqr6JBTk6V4RS6vteW1lAXWMLN0/paztKu2hBdLLRad0ZkxbLS9/soblFT3lVSjnUNTYzb0UBZwxIYEBitO047aIF4QY3Ts6g4FANn27VuSKUUg6L1pVw8Gg9t/jI1gNoQbjFtKG9SIkN5/mv9ZRXpZTjwrjnvtrF4KRuTOrfw3acdtOCcIOgwABumJTO6t3lrN2rF84p5e8+317GjgNHmXN6hldfGHc8LQg3mZmdRrewIOZ+uct2FKWUZc99uYte3cKYPsL75nw4ES0IN4kKDeLa8X34eHMpuw9W246jlLJkU3El3+w8xI2T0wkO9K1fub6V1sfMnpROcEAAz3+lWxFK+avnvtpFVGgQM7O9c86HE9GCcKOe0WFcOiaF+blFHNQZ55TyO8WHa1m8YR9XZafSLSzYdpwO04Jws1tO70tjc4sOv6GUH3rJeSbj7EkZlpOcGi0IN+uXEMW5gxN5ZUUB1Tr8hlJ+o7KmkTdX72X6iCRSYsNtxzklWhAe8PMz+lFZ28hba3T4DaX8xWurCqhuaObnp/ezHeWUaUF4wGl9upOdHscLX+2isVnnrVaqq6trbOal5bs5Y0ACQ5K72Y5zyrQgPOTWM/tSUlnHonU6b7VSXd2C3CIOHm3g1jN8d+sBtCA85qyBPRmYGM0/vtyp81Yr1YU1tziG1RjZO4bxfb13vun20ILwEBHh52f0Zfv+oyzLO2A7jlLKTT7eVErBoRpuPaOfTw2r4YoWhAf9dGQyKbHhPPP5TttRlFJuYIzh2S92khEfyXlDe9mO86NpQXhQcGAAt0zJYM2eCtbsKbcdRynVyb7OP8jG4krmnN6XwADf3noALQiPu3JsGj0iQ3h6Wb7tKEqpTvb0sp0kdgvl0jEptqN0Ci0IDwsPCeSGSeksyytjS8kR23GUUp1k7d4KVuw6xM2T+xIaFGg7TqfQgrDgugnpRIUG8cwXeixCqa7i6c93EhMezFXjfG9QvrZoQVgQEx7MNePT+GBDCXt0KHClfN72/VUs3bKfWRMdf/x1FVoQltw0OYOgwAD+8aVuRSjl6579fCfhwYHcMDHddpROpQVhSc/oMK7I6s2C3CJKDtfajqOUOkUFh6pZuL6Eq8el0T0yxHacTqUFYdFtZ/YH0OsilPJhTy/bSWCA8PPT+9qO0um0ICxKiQ3nstNSeXtNIaWVdbbjKKU6qLC8hne/LeLq7DR6dguzHafTaUFYdvuZ/WhxXn2plPItT3++kwDnMDpdkfWCEJFYEVkgIttEZKuITBCROBFZKiI7nJ+7287pLqlxEVw6JoU3Vu/lwBHdilDKVxQfrmVBbiFXjk0lKcY3JwQ6GesFATwJfGyMGQSMBLYC9wOfGmMygU+d97usO87qT3OL4dkvdtmOopRqp2edxw5vPdO3h/Q+EasFISIxwOnACwDGmAZjzGFgBjDPudg84GI7CT2jT49ILh6VwuurCjhQpVsRSnm7ksO1vL2mkMtOS/XZ6UTbw/YWRAZQBrwkImtF5HkRiQQSjTH7nMuUAomuvlhE5ohIjojklJWVeSiye/zi7P40Nrfw3Je6FaGUt3tqWT4Gwy/O7m87ilvZLoggYAzwjDFmNFDNcbuTjGN2HZcz7Bhj5hpjsowxWQkJCW4P604Z8ZHMGJXCayv3cvBove04Sqk2FJbX8E6O49hDV956APsFUQQUGWNWOe8vwFEY+0UkCcD52S9m2LnjrP7UNTXz/Fe7bUdRSrXhqWX5CMIdZ3XtrQewXBDGmFKgUEQGOh+aCmwBFgGznI/NAhZaiOdx/XtG8dMRybyyYg/l1Q224yiljrP3UA3zc4u4KrvrnrnUmu0tCID/AF4XkQ3AKOD3wB+Bc0VkB3CO875f+I+z+1Pb2MwLX+uxCKW8zd8+20FggHC7H2w9gOMYgFXGmHVAlounpno6izfITIzmguFJvLx8DzdN7ktcFxvbRSlftftgNe+tLeb6CX1I7IJXTbviDVsQ6ji/nJpJTWMz/9Crq5XyGn/9dAfBgcJtXfi6h+NpQXihzMRoLhmVwrwVe/TqaqW8QP6BKhauK+b6Cen0jPaPrQfQgvBad52TSVOz4e86d7VS1j35aT5hwYFdcsTWE9GC8FJ9ekRyeVYqb67eS1FFje04SvmtvNIqFm8oYfbEdHpEhdqO41FaEF7szqn9ERH++ukO21GU8ltPfrqdyJAgbpniX1sPoAXh1ZJiwrlmXBoLcovYWXbUdhyl/M6m4ko+3FjKjZPSu9xsce2hBeHl7jirP2HBgTy+dLvtKEr5nUeX5BEbEczNfnbs4RgtCC8XHxXKTZMz+GDDPjYVV9qOo5TfWLXrEF9sL+O2M/rRLSzYdhwrtCB8wM1T+hITHsxj/86zHUUpv2CM4ZEleSR2C2XWxHTbcazRgvABMeHB3HpGP5bllbFmT7ntOEp1eZ9tO0BuQQV3Ts0kLDjQdhxrtCB8xOyJ6SREh/Lox3k4RkBXSrlDS4vh0SV5pPeI4IqsVNtxrNKC8BHhIYHceXZ/Vu8pZ1meX4x+rpQV760tZltpFfecN5DgQP/+Fdnu715EnhCRUe4Mo05sZnYaGfGR/PGjbTS36FaEUp2ttqGZPy/JY2TvGKYPT7Idx7qO1GMgsERENonIfSLS212hlGvBgQHc+5OBbN9/lHdzi2zHUarLee6rXZQeqeO/pg8hIEBsx7Gu3QVhjLkTSMYxJegoYKuIfCIi14tIlLsCqu+bNqwXo9NieWxpHrUNzbbjKNVlHDhSx7Nf7GTa0F6MTY+zHccrdGgHmzGm2Riz2BhzFTAeSABeBkpF5HkRSXFDRtWKiPCb8wez/0g9Ly7XqUmV6iyPL91OY3ML958/yHYUr9GhghCRbiJyk4gsA74EVgFTgMHAUeCjzo+ojpedEce5QxJ55vOdHDpabzuOUj4vr7SKd3IKuW58OunxkbbjeI2OHKReABQDlwLPAsnGmDnGmOXGmELgHiDDPTHV8e6bNojaxmae+ESH4FDqx/rDR1uJCg3izqn+MZVoe3VkC2IlkGmMudAY87Yx5nt/uhpjWoDETk2n2tS/ZxTXje/DG6v2kldaZTuOUj5ref5BPs8r4xdn9yc2wv8G5DuRjhyk/rMxpvQky+jEBR5019RMosOC+Z8PtujFc0qdgpYWwx8+2kpKbDjXT0i3Hcfr+PdVID6ue2QId03N5KsdB/XiOaVOwaL1JWwqPsKvfjLAr4fUaIsWhI+7bkIf+sZH8j8fbKWxucV2HKV8Rl1jM48uyWNocjdmjNQTMF3RgvBxwYEB/PaCwewqq+a1lQW24yjlM15cvpviw7X85vzBelFcG7QguoCpg3syJTOeJ5Zup7y6wXYcpbze/iN1/P2zfM4ZnMjkzHjbcbyWFkQXICI8OH0I1Q3NPL5U54xQ6mT++NE2mpoN/z19sO0oXk0LoovITIz+7rTXLSVHbMdRymvlFlTw/tpibp6SQZ8eelHciWhBdCF3nzOAmPBgfrd4s572qpQLLS2GhxZtJrFbKHecpRfFnYwWRBcSExHMPecNZOWucj7adMJLVpTyS/NzC9lYXMlvzh9MZGiQ7TheTwuii7lqbCqDekXzvx9s1dFelWrlcE0Df/o4j6w+3ZkxKtl2HJ+gBdHFBAUG8NBFQyk+XMs/vtxpO45SXuPxpds5XNPA72YMQ0RPa20PLYguaHzfHkwfkcQzn++kqEJHP1Fqc0klr60s4LrxfRiS3M12HJ/hFQUhIoEislZEFjvvZ4jIKhHJF5G3RURH0Oqg314wGBH4w4fbbEdRyipjDA8u3Ez3iBDuOXeg7Tg+xSsKArgL2Nrq/p+AJ4wx/YEK4CYrqXxYcmw4t5/Znw827uOb/IO24yhlzXvfFpNbUMF90wYRExFsO45PsV4QzrmtLwSed94X4GxggXORecDFdtL5tjmn9yUtLoL/WriJ+iY9YK38z+GaBn7/4VZGp8Vy2Wm9bcfxOdYLAvgLcC9wbKS5HsBhY0yT834R4HIkLRGZIyI5IpJTVlbm/qQ+Jiw4kN/NGMqusmqe+3KX7ThKedyjS/KoqGngfy4epuMtnQKrBSEi04EDxpjcU/l6Y8xcY0yWMSYrISGhk9N1DWcO7MkFw3vxt8/y2XtID1gr/7Gu8DBvrN7L7IkZDE2OsR3HJ9negpgEXCQie4C3cOxaehKIFZFjV7H0xjHVqTpFD04fSlCA8OCiTXqFtfILTc0tPPD+RnpGh3L3uZm24/gsqwVhjPmNMaa3MSYdmAl8Zoy5BlgGXOZcbBaw0FLELqFXTBh3nzuAz/PK+HCjXmGtur5XVxawueQI/z19CNFhemD6VNnegmjLfcA9IpKP45jEC5bz+LzZE9MZmtyNh/61mcqaRttxlHKbksO1/HlJHqcPSODC4Um24/g0rykIY8znxpjpztu7jDHZxpj+xpjLjTH1tvP5uqDAAP70sxGUVzfwx4+3nvwLlPJBjmseNtFsDP97sV4x/WN5TUEo9xuWEsNNkzN4c3UhK3Yesh1HqU738aZSPtl6gHvOHUBqXITtOD5PC8LP3H3OANLiIvjt+xupa9RrI1TXUVnbyP9ZtJkhSd24cVKG7ThdghaEnwkPCeT3lwxn98Fq/vLJDttxlOo0j3y8jYNH6/njz4YTFKi/2jqDrkU/NDkzniuzUpn75U7W7q2wHUepH2317nJeX7WXGyZlMKJ3rO04XYYWhJ96YPpgenUL41fz1+uuJuXT6hqbuf/dDaTGhfOf5w2wHadL0YLwU93CgvnTZSPYWVbN40u3246j1Cn7+2f57DpYze8vGU5EiM4S15m0IPzYlMwErh6XxnNf7SJnT7ntOEp12NZ9R3j2i538bExvpmTqcDudTQvCz/32gsGkxIbz6wUbdIpS5VMamlr49YL1xIQH818XDrYdp0vSgvBzUaFBPHLZCHYfrObP/86zHUepdvvrpzvYVHyE3186nO6ROqeYO2hBKCb2i+e68X14cflu1uiuJuUDcgvKefrzfK7I6s1PhvayHafL0oJQANx//iB6dw/n1/PX664m5dWq65u4++31JMeG89/Th9iO06VpQSgAIkODeORnI9lzqIZHlug81sp7Pbx4C4UVNTx+xSgdqdXNtCDUdyb068Hsiem8tHwPX+3QGfqU9/lo4z7eWlPIrWf0IzsjznacLk8LQn3P/ecPon/PKH41fz0V1Q224yj1nX2Vtdz/3kZG9I7h7nP0gjhP0IJQ3xMWHMhfrhxFeXUDv31/o85Ap7xCc4vh7rfX0djcwpMzRxMSpL+6PEHXsvqBYSkx/Od5A/loUynzc4tsx1GKf3y5k5W7ynnooqFkxEfajuM3tCCUS7dM6cv4vnE8tGgzO8uO2o6j/FhuQQWP/Xs7Fw5P4vLTetuO41e0IJRLgQHCX64cTWhQAHe8/q0O6KesqKxp5M4315IUE8bvLx2uM8R5mBaEalOvmDAeu2Ik20qr+N8PdJpS5VnGGO57dwP7j9Tx96vHEBOup7R6mhaEOqGzByVy8+QMXl1ZwEcb99mOo/zIa6v28vHmUu6dNpBRqTrHgw1aEOqk7p02iJG9Y7j33Q3sPVRjO47yA5tLKnl48RbOHJjAzZP72o7jt7Qg1EmFBAXw96vHAHDHG99S36THI5T7HK1v4hdvrKV7RDCPXT6SgAA97mCLFoRql9S4CB67fCQbiyv1eIRyG2MMD7y/kYJD1fx15mh6RIXajuTXtCBUu503tBe3TMnglRUFLN5QYjuO6oLeySlk4boS7j5nAOP69rAdx+9pQagOuXfaIE7r0537Fmxg+/4q23FUF7KxqJIHF25mUv8e3H5Wf9txFFoQqoOCAwN46uoxRIQGMeeVHCprGm1HUl3Agao65ryaQ3xUKE/OHE2gHnfwCloQqsN6xYTx7LVjKD5cy51vraW5RcdrUqeuvqmZ2177loqaBv5x3WnE63EHr6EFoU7JaX3i+N2MYXyxvYxHl+hUperUGGN4aNFmcgsqePSykQxLibEdSbUSZDuA8l1XZaexuaSSZ7/YyeCkaGaMSrEdSfmYN1bv5c3Vhdx2Zj9+OjLZdhx1HN2CUD/Kg9OHkp0ex70LNrCxqNJ2HOVDcgsqeGjRZs4YkMCvzhtoO45ywWpBiEiqiCwTkS0isllE7nI+HiciS0Vkh/Nzd5s5VdtCggJ4+toxxEeFMufVHMqq6m1HUj7gwJE6bnstl6SYcP6qB6W9lu0tiCbgP40xQ4DxwB0iMgS4H/jUGJMJfOq8r7xUfFQoc68/jYqaBm57LVevtFYnVN/UzO2vf0tVXRNzrz+NmAgdhM9bWS0IY8w+Y8y3zttVwFYgBZgBzHMuNg+42E5C1V5Dk2N47PJR5BRU8Ov5G2jRM5uUCy0thl/N30BOQQWPXDaCQb262Y6kTsD2FsR3RCQdGA2sAhKNMceGDi0FEtv4mjkikiMiOWVlZR7Jqdp24Ygk7p02kEXrS3hsqZ7ZpH7oDx9t5V/rS7j//EF6UNoHeEVBiEgU8C7wS2PMkdbPGcekyC7/HDXGzDXGZBljshISEjyQVJ3MbWf046rsVJ5atpO3Vu+1HUd5kRe/3s1zX+1m1oQ+/Px0HaHVF1g/zVVEgnGUw+vGmPecD+8XkSRjzD4RSQIO2EuoOkJEeHjGMEoO1/HAPzeREB3K1MEuNwCVH1m4rpiHP9jCT4Ym8uBPh+rMcD7C9llMArwAbDXGPN7qqUXALOftWcBCT2dTpy4oMICnrhnD0ORu3P76t6zeXW47krJo2bYD/Oc768lOj9NhNHyM7V1Mk4DrgLNFZJ3z4wLgj8C5IrIDOMd5X/mQqNAgXr4hm5Tu4dz08ho2l+g1Ev5ozZ5ybns9l0FJ0Tw/K4uw4EDbkVQHiGMXv+/LysoyOTk5tmOo45QcruWyZ76hodmw4NYJpMdH2o6kPGRzSSUz564kITqU+T+foHM7eCkRyTXGZLl6zvYWhOrikmPDeeWmcbQYw3UvruLAkTrbkZQH7Co7yvUvrCY6NIhXbxqn5eCjtCCU2/XvGcVLs8dy6GgD17+4WocI7+KKD9dy7fOrEIHXbh5HSmy47UjqFGlBKI8YmRrL3Ouy2FVWzU3z1lDboFdbd0VlVfVc+/wqquqbmHdjNn0TomxHUj+CFoTymMmZ8Txx5Si+3VvBDS+vpqahyXYk1YkOHq3n6udWUlpZx0uzxzI0WYfu9nVaEMqjLhyRxBNXjmL17nJmv7iGo/VaEl1BeXUD1z6/isKKGl6cPZas9DjbkVQn0IJQHjdjVApPzhxN7t4KZr24mqo6PSbhyyqqG7jm+VXsPljNC7PGMqFfD9uRVCfRglBW/HRkMn+/ajTrCw9z9XOrKK9usB1JnYL9R+q4cu4KdpYdZe71WUzqH287kupEWhDKmvOHJzH3+tPYvr+KK/6xgtJKPQXWlxQcquZnz3xDcUUtL98wljMG6HhoXY0WhLLq7EGJzLsxm32Ha7ns2W/Yc7DadiTVDlv3HeGyZ1dwtL6JN24Zz8R+uuXQFWlBKOvG9+3Bm3PGU13fxGXPfsOmYh2Ww5t9k3+QK55dQYDA/J9PYGRqrO1Iyk20IJRXGNE7lvm3TiQkMICZc1fyTf5B25GUCwvXFTPrpdUkxYbx/u2TyEyMtgF6ewIAAA2+SURBVB1JuZEWhPIa/XtG8e7tE0mODWP2S2tYuK7YdiTlZIzh6c/zueutdYxJ6878WyeSrFdId3laEMqrJMWE887PJzAqNZa73lrHo0u26fSlljU0tXDfuxt45OM8fjoymVduyiYmXOeR9gdaEMrrxEaE8NrN45g51jEz3ZxXc/RaCUsqaxqZ9eJq3skp4s6pmfx15ihCg3TIbn+hBaG8UkhQAH+4dDj/96KhLMsrY8ZTy9m+v8p2LL+yuaSSi576mtyCCp64ciT3nDtAZ4LzM1oQymuJCLMmpvPaTeM4UtvEjL8v559r9biEJ8zPKeTSp7+hvrGFN+eM45LRvW1HUhZoQSivN6FfDz68czLDU2L45dvreHDhJhqaWmzH6pLqGpu5/90N/HrBBk7r053Fd07mtD46rpK/CrIdQKn26NktjDduGccjS/KY++UuNhZX8sw1p9ErJsx2tC4j/8BR7nj9W/L2V3H7mf2459wBBAXq35D+TH/6ymcEBQbw2wsG8/Q1Y9heWsX0v33Fcr1e4kczxrAgt4iL/v41ZUfrmXdjNvdOG6TloLQglO+5YHgSC38xiZjwYK55fhX3v7uBylo9y+lUlFXVM+fVXH41fz3DUmL48M4pOqaS+o7uYlI+qX/PaBb/xxT+8sl2nvtqF59uO8DDM4YxbVgv29F8gjGGxRv28eDCTVQ3NPPABYO5cXIGgQF6lpL6/8SYrnERUlZWlsnJybEdQ1mwqbiSexdsYMu+I1w4Ion/e9FQ4qNCbcfyWiWHa/nvf27i020HGNE7hsevGEn/njpkhr8SkVxjTJbL57QgVFfQ2NzC3C938eQnO4gMDeTBnw5hxsgUAvQv4u80Nbfw6soC/rwkjxYD95w7gBsmpeuxBj+nBaH8xvb9Vfx6wQbWFx5mZO8YfnvBYMb11RnOvtpRxsOLt7B9/1GmZMbz+0uGkxoXYTuW8gJaEMqvNLcY3l9bzJ+X5FF6pI5zhyRy37RB9O8ZZTuax+WVVvHokm18svUAaXERPHDhYM4bkqhXRKvvaEEov1Tb0MyLy3fzzOc7qW1sZubYVO46J5Oe0V3/2om9h2p44pPt/HNdMVGhQdx+Zn9unJyu4yipH9CCUH7t0NF6/vZZPq+tLCAoULhkdAqzJ2YwsFfXOzC7Y38Vz3y+k4XrSwgOFGZPzODWM/oSGxFiO5ryUloQSgG7D1bzjy928v7aYuqbWpjUvwezJ2Zw9qCePn16Z0uL4Zudh5i3Yg9Lt+wnPDiQq8elMef0viR26/pbS+rH0YJQqpXy6gbeWrOXV74poPRIHWlxEVw/oQ8Xj07xqdNjy6sbeO/bIl5ftZfdB6uJjQjm+gnpzJ6YTlykbjGo9tGCUMqFxuYW/r15Py8t301OQQWBAcLk/vHMGJXMeUN7ERXqfdeR1jc18/WOg8zPKeLTbftpbDac1qc7145P4/xhSYQF6zEG1TFaEEqdxPb9VfxzbTEL15VQfLiW0KAAzh7Uk+kjkpnUv4fVffj7KmtZtq2MZXkHWJ5/kJqGZnpEhnDJ6BQuz0rtksdSlOf4ZEGIyDTgSSAQeN4Y88cTLa8FoTqDMYbcggoWb9jH4g37OHi0HoCBidFkpXdnRO8YhibHkJkY5ZYzgowxHKiqZ1NxJTkFFSzbdoBtpY6JklJiwzlrUAJnDezJlMwEQoL0Ajf14/lcQYhIILAdOBcoAtYAVxljtrT1NVoQqrM1tzjKYvXuQ6zeU8G3BRUcrW8CIChAyEyMZmhyN4YmdyMtLoIeUaH0iAyhe2QIkSGBJ7zWoK6xmeLDtRSW11BwqIadZUfZWXaUvNKj35VSUICQld6dswb25KxBPcnsGaXXL6hOd6KC8L6drA7ZQL4xZheAiLwFzADaLAilOltggJCdEUd2hmPCnJYWQ0F5DZtLKtlccoTNJUdYtu0AC3KLfvC1QQFCTHgw4SGBBAUIAQFCS4uhpqGZ2sZmjtY30fpvs+jQIPr2jOKMAQkMS+nGsJQYBid188rjIMp/eOu7LwUobHW/CBh3/EIiMgeYA5CWluaZZMpvBQQIGfGRZMRHMn1EMvD/dwntq6zj0NF6Dh6t53BNI5W1jRyubaSusZnmFkNTiyFQhIiQQMKCA+keEUJqXDhpcRGkxUWQEB2qWwfK63hrQbSLMWYuMBccu5gsx1F+SERI7Bam1xuoLslbj3IVA6mt7vd2PqaUUspDvLUg1gCZIpIhIiHATGCR5UxKKeVXvHIXkzGmSUR+ASzBcZrri8aYzZZjKaWUX/HKggAwxnwIfGg7h1JK+Stv3cWklFLKMi0IpZRSLmlBKKWUckkLQimllEteORbTqRCRMqDgFL88HjjYiXE6i+bqGM3Vcd6aTXN1zI/J1ccYk+DqiS5TED+GiOS0NViVTZqrYzRXx3lrNs3VMe7KpbuYlFJKuaQFoZRSyiUtCIe5tgO0QXN1jObqOG/Nprk6xi259BiEUkopl3QLQimllEtaEEoppVzym4IQkctFZLOItIhI1nHP/UZE8kUkT0R+0sbXZ4jIKudybzuHIe/sjG+LyDrnxx4RWdfGcntEZKNzObdPxC0iD4lIcatsF7Sx3DTnOswXkfs9kOtREdkmIhtE5H0RiW1jOY+sr5N9/yIS6vwZ5zvfS+nuytLqNVNFZJmIbHG+/+9yscyZIlLZ6uf7oLtzOV/3hD8Xcfirc31tEJExHsg0sNV6WCciR0Tkl8ct47H1JSIvisgBEdnU6rE4EVkqIjucn7u38bWznMvsEJFZpxTAGOMXH8BgYCDwOZDV6vEhwHogFMgAdgKBLr7+HWCm8/azwG1uzvsY8GAbz+0B4j247h4CfnWSZQKd664vEOJcp0PcnOs8IMh5+0/An2ytr/Z8/8DtwLPO2zOBtz3ws0sCxjhvRwPbXeQ6E1jsqfdTe38uwAXAR4AA44FVHs4XCJTiuJDMyvoCTgfGAJtaPfYIcL/z9v2u3vdAHLDL+bm783b3jr6+32xBGGO2GmPyXDw1A3jLGFNvjNkN5APZrRcQx2TBZwMLnA/NAy52V1bn610BvOmu13CDbCDfGLPLGNMAvIVj3bqNMebfxpgm592VOGYetKU93/8MHO8dcLyXpoqbJ6I2xuwzxnzrvF0FbMUx57svmAG8YhxWArEikuTB158K7DTGnOoIDT+aMeZLoPy4h1u/j9r6XfQTYKkxptwYUwEsBaZ19PX9piBOIAUobHW/iB/+B+oBHG71y8jVMp1pCrDfGLOjjecN8G8RyRWROW7M0dovnJv5L7axSdue9ehON+L4a9MVT6yv9nz/3y3jfC9V4nhveYRzl9ZoYJWLpyeIyHoR+UhEhnoo0sl+LrbfUzNp+480G+vrmERjzD7n7VIg0cUynbLuvHbCoFMhIp8AvVw89YAxZqGn87jSzoxXceKth8nGmGIR6QksFZFtzr803JILeAZ4GMd/6Idx7P668ce8XmfkOra+ROQBoAl4vY1/ptPXl68RkSjgXeCXxpgjxz39LY7dKEedx5f+CWR6IJbX/lycxxgvAn7j4mlb6+sHjDFGRNx2rUKXKghjzDmn8GXFQGqr+72dj7V2CMfmbZDzLz9Xy3RKRhEJAi4FTjvBv1Hs/HxARN7HsXvjR/3Hau+6E5HngMUunmrPeuz0XCIyG5gOTDXOna8u/o1OX18utOf7P7ZMkfPnHIPjveVWIhKMoxxeN8a8d/zzrQvDGPOhiDwtIvHGGLcOSteOn4tb3lPtdD7wrTFm//FP2FpfrewXkSRjzD7nLrcDLpYpxnGs5JjeOI6/dojuYoJFwEznGSYZOP4SWN16AecvnmXAZc6HZgHu2iI5B9hmjCly9aSIRIpI9LHbOA7UbnK1bGc5br/vJW283hogUxxne4Xg2Dxf5OZc04B7gYuMMTVtLOOp9dWe738RjvcOON5Ln7VVap3FeYzjBWCrMebxNpbpdexYiIhk4/i94NbiaufPZRFwvfNspvFAZatdK+7W5la8jfV1nNbvo7Z+Fy0BzhOR7s5dwuc5H+sYTxyJ94YPHL/YioB6YD+wpNVzD+A4AyUPOL/V4x8Cyc7bfXEURz4wHwh1U86XgVuPeywZ+LBVjvXOj804drW4e929CmwENjjfnEnH53LevwDHWTI7PZQrH8d+1nXOj2ePz+XJ9eXq+wd+h6PAAMKc751853uprwfW0WQcuwY3tFpPFwC3HnufAb9wrpv1OA72T/RALpc/l+NyCfCUc31upNXZh27OFonjF35Mq8esrC8cJbUPaHT+/roJx3GrT4EdwCdAnHPZLOD5Vl97o/O9lg/ccCqvr0NtKKWUckl3MSmllHJJC0IppZRLWhBKKaVc0oJQSinlkhaEUkopl7QglFJKuaQFoZRSyiUtCKWUUi5pQSjlBiLST0TKj01yIyLJIlImImdajqZUu+mV1Eq5iYjcAtyNYwiE94GNxphf2U2lVPtpQSjlRiKyCMdMhQYYa4yptxxJqXbTXUxKuddzwDDgb1oOytfoFoRSbuKcpGc9jqHizweGG2OOnz5SKa+lBaGUm4jIC0CUMeZKEZkLxBpjrrCdS6n20l1MSrmBiMzAMUn8bc6H7gHGiMg19lIp1TG6BaGUUsol3YJQSinlkhaEUkopl7QglFJKuaQFoZRSyiUtCKWUUi5pQSillHJJC0IppZRLWhBKKaVc+n871XFFmJxURwAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "plt.plot(x, y)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.ylabel('y', fontsize=12)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As already stated ``maxsmooth`` does not constrain the first derivative of the DCF by default so we can go ahead and fit the data." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 2.1448731422424316\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [-1 -1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 0.04927823450747571\n", - "Parameters: [[ 1.17731858e-02 2.02215641e-01 1.00004968e+00 3.64579570e-06\n", - " -4.01724980e-07 3.79943911e-08 -2.52386154e-09 1.08957701e-10\n", - " -2.74734089e-12 3.07852441e-14]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 1, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - } - ], - "source": [ - "from maxsmooth.DCF import smooth\n", - "\n", - "res = smooth(x, y, N)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we than plot the resultant residuals we will see that despite the data having a turning point present we have recovered the Gaussian noise." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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LAsNSStBnhTmFOVMKpoNfiDrExPL9COOWBYAPM/jjjvu4LzzzgPgXe96F1/5ylfYtGkTn/vc53jve98LwBVXXMFpp53Ggw8+yAMPPMDhhx/Opk2b+Pa3v819993Hvffeyze+8Q3+8Ic/sH79em666abqa9x0002sX7+e2267jS1btvD73/+ezZs3s2nTJu6++24AtmzZwnvf+14effRRnnjiiZb7bdq0ie9///ts3ryZW2+9lfvvv7/t+8pkMlx22WV86Utfqtvebs1RfO973+Oss85i8+bNPPjgg6xdu5bdu3dzzTXXcPvtt/PAAw+wbt06vvCFLzS/sOrJWEjOgTEChIOBUyUWTw8K9iWZqBN2jDE9iCOWcWAikcV0olgssnbtWl544QUOPfRQzjzzTPL5PPfccw8XXnhhdb9yuQzAnXfeyXe+8x0gqM9ks1l+85vfcMEFF5BOBwXKt7zlLfz617/miiuuYOfOnbz44ovs2rWLrq4uVq5cyZe+9CVuu+02jj76aADy+Txbtmxhn332Yd999+WEE04A4Lbbbmu53/DwMBdccAGpVOB5EZJhO1xxxRWsXbuWD37wg9Vt7dYcvhbAq171Ki677DJc1+X8889n7dq1/OpXv+KPf/wjJ598MgCO43DiiSe2eFXFLDGxLDgkFbFM1e6gYiShDCUSdBhxxDLdiIllHiOssRQKBc466yy++tWvcumll5LL5di8efOUn//CCy/k5ptv5qWXXmL9+vVAUD/58Ic/zLvf/e66fbdu3Vo90Y+23xe/+MUJrSGXy/H2t799wvWjU089lbvvvpuf/vSnXHrppVx55ZV0dXVx5plnsmHDhtEfHNZYFpBceowA1YjFmNoogFQeLCVM+uKIZdoRf6ILAKlUii9/+ct8/vOfJ5VKsWrVKn7wgx8AwQn+wQcfBOCMM87g+uuvB4L02eDgIKeccgo//OEPKRQKjIyMcMstt3DKKacAsH79er7//e9z8803VyOgs846i29961vk84HzwAsvvFDXuRWi3X6nnnoqP/zhDykWiwwPD/OTn/xkzPd35ZVX8rWvfY1KpQIw6ppDPPvssyxevJh3vvOdXH755TzwwAOccMIJ/Pa3v+XJJ58EYGRkhD/96U9NrxfWWERcY1lwWNGVoitlTjliCYklrrHMDOKIZYHg6KOP5qijjmLDhg1897vf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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(x, y- res.y_fit, label='Recovered Noise')\n", - "plt.plot(x, noise, label='Actual Noise')\n", - "plt.ylabel(r'$\\delta y$', fontsize=12)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.legend()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To illustrate what happens when there is an inflection point in the data we can define some sinusoidal data as so." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "x = np.linspace(1, 5, 100)\n", - "noise = np.random.normal(0, 0.02, 100)\n", - "y = np.sin(x) + noise\n", - "\n", - "N = 10\n", - "\n", - "plt.plot(x, y)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.ylabel('y', fontsize=12)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we proceed to fit this with smooth() in its default settings we will get a poor fit as by default the second derivative is constrained. We need to lift this constraint to allow for the prominent inflection point to be modelled. We do this by setting the keyword argument constraints=3 creating a Partially Smooth Function\n", - "or PSF.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.616485357284546\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 8\n", - "Signs : [ 1 -1 1 -1 1 -1 1 -1]\n", - "Objective Function Value: 1.2278492797034808\n", - "Parameters: [[ 1.34984313e-01 -7.37897372e-01 -1.35984051e-02 1.60265401e-02\n", - " -1.21425226e-02 6.13320573e-03 -2.06526186e-03 4.47071803e-04\n", - " -5.64542010e-05 3.16834713e-06]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 2\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 0, '1': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n", - "#############################################################\n", - "#############################################################\n", - "----------------------OPTIMUM RESULT-------------------------\n", - "Time: 1.062380313873291\n", - "Polynomial Order: 10\n", - "Number of Constrained Derivatives: 7\n", - "Signs : [-1 -1 1 -1 1 -1 1]\n", - "Objective Function Value: 0.02853207306425321\n", - "Parameters: [[ 1.16343093e-01 -9.58117300e-01 -4.87723262e-02 1.31696692e-01\n", - " 1.23367766e-03 -6.19895817e-04 2.08513389e-04 -4.51222389e-05\n", - " 5.69694366e-06 -3.19689176e-07]]\n", - "Method: qp-sign_flipping\n", - "Model: difference_polynomial\n", - "Constraints: m >= 3\n", - "Zero Crossings Used? (0 signifies Yes\n", - " in derivative order \"i\"): {'0': 0, '1': 0, '2': 0}\n", - "-------------------------------------------------------------\n", - "#############################################################\n" - ] - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "res_msf = smooth(x, y, N)\n", - "res_psf = smooth(x, y, N, constraints=3)\n", - "\n", - "plt.plot(x, y, label='Data')\n", - "plt.plot(x, res_msf.y_fit, label=r'MSF fit, $m \\geq 2$')\n", - "plt.plot(x, res_psf.y_fit, label=r'PSF fit, $m \\geq 3$')\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.ylabel('y', fontsize=12)\n", - "plt.legend()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we can plot the residuals to further see that by lifting the constraint on the second derivative we have allowed an inflection point in the data." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZYAAAEJCAYAAAC3yAEAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nOy9eZgc1X3u/zld1d3Vy+warSMhYRAGBBKrwWExISzesLHDBdtZ+NkOTrwlIXawr30dk+DENjEGfIlXvMW2wFYCXiA2ZgcDYl8khJCQhDRaZp/eu6u66vz+OFXd1TM9Mz2bZqRb7/PMM91V1dWnu6vOe97vKqSUBAgQIECAADOF0FwPIECAAAECHF4IiCVAgAABAswoAmIJECBAgAAzioBYAgQIECDAjCIglgABAgQIMKPQ53oA8wELFiyQK1eunOthBAgQIMAhhWeeeaZfStk5cntALMDKlSt5+umn53oYAQIECHBIQQjxer3tgSksQIAAAQLMKAJiCRAgQIAAM4qAWAIECBAgwIwi8LEECBBgRmBZFt3d3RSLxbkeSoAZhmEYdHV1EQ6HGzo+IJYAAQLMCLq7u2lqamLlypUIIeZ6OAFmCFJKBgYG6O7uZtWqVQ29JjCFBQgQYEZQLBbp6OgISOUwgxCCjo6OSSnRgFgCBAgwYwhI5fDEZH/XgFgCVDG0C7bfO9ejCBAgwCGOgFgCVPHEt+C/PjzXowgQYMrQNI1169axZs0a3vnOdzI8PDzXQ5o0vvjFL/Lv//7vdbfH43F6e3sr25LJ5ITne/Ob3zyj42sEAbEEqKJcAKsw16MIEGDKiMViPP/882zatIn29nZuueWWuR4SoBzgjuNM+zwLFizga1/72qRe89hjj037fSeLeUksQoiLhRBbhRDbhRCfqbM/KoS43d2/UQix0rfvRCHE40KIzUKIl4QQxsEc+yGNsgm2OdejCBBgRnDmmWeyd+9eAF577TUuvvhiTjnlFM4++2xeeeUVAHp6erj00ktZu3Yta9eurUzCN9xwA2vWrGHNmjXceOONAHzmM5+pISq/srj++us57bTTOPHEE/mnf/onAHbt2sUxxxzDX/zFX7BmzRr27NlT9ziAL33pS6xevZqzzjqLrVu3jvmZPvjBD3L77bczODg4al+9MUNV1ezfv59zzjmnougeeeQRAO655x7OPPNMTj75ZC677DKy2ewkv+nRmHfhxkIIDbgFuADoBp4SQvxKSvmy77APAUNSyqOEEFcAXwEuF0LowE+AP5dSviCE6ACsg/wRDl3YJkgH7DJo8+7SCHAI4dpfb+blfekZPedxS5v5p3ce39Cxtm1z33338aEPfQiAq666im9961scffTRbNy4kY9+9KPcf//9fPKTn+Tcc8/ljjvuwLZtstkszzzzDD/4wQ/YuHEjUkre9KY3ce6553L55Zfzd3/3d3zsYx8D4Oc//zm/+93vuOeee9i2bRtPPvkkUkouueQSHn74YVasWMG2bdv40Y9+xBlnnDHmcYlEgttuu43nn3+ecrnMySefzCmnnFL3cyWTST74wQ9y0003ce2111a2jzXmk046qXLMz372My666CI+97nPYds2+Xye/v5+rrvuOu69914SiQRf+cpXuOGGG/jCF74w1Z8JmIfEApwObJdS7gAQQtwGvAvwE8u7gC+6jzcA/1eosIULgRellC8ASCkHDtagDwt4asU2A2IJcEiiUCiwbt069u7dy7HHHssFF1xANpvlscce47LLLqscVyqVALj//vv58Y9/DCj/TEtLC48++iiXXnopiUQCgPe85z088sgjfPKTn6S3t5d9+/bR19dHW1sby5cv56abbuKee+6pTOLZbJZt27axYsUKjjjiCM444wxAKYN6x2UyGS699FLi8TgAl1xyybif8ZOf/CTr1q3jU5/6VGXbWGP2E8tpp53GBz/4QSzL4t3vfjfr1q3joYce4uWXX+aP/uiPADBNkzPPPHOK334V83H2WAbs8T3vBt401jFSyrIQIgV0AKsBKYT4HdAJ3Cal/Gq9NxFCXAVcBbBixYoZ/QCHLGxX3NklID6nQwlwaKNRZTHT8Hws+Xyeiy66iFtuuYUrr7yS1tZWnn/++Wmf/7LLLmPDhg0cOHCAyy+/HFD+k89+9rN85CMfqTl2165dlYl+vOP8ZqtG0Nrayvvf//5J+4/OOeccHn74Ye666y6uvPJKrr76atra2rjgggtYv379pM41Eealj2Ua0IGzgA+4/y8VQpxf70Ap5XeklKdKKU/t7BzVTuD/TVQUS2A9DHBoIx6Pc/PNN/O1r32NeDzOqlWr+MUvfgGoCf6FF14A4Pzzz+eb3/wmoMxnqVSKs88+mzvvvJN8Pk8ul+OOO+7g7LPPBuDyyy/ntttuY8OGDRUFdNFFF/H973+/4pvYu3dvTeSWh7GOO+ecc7jzzjspFApkMhl+/etfT/j5rr76ar797W9TLpcBxh2zh9dff51FixbxV3/1V3z4wx/m2Wef5YwzzuAPf/gD27dvByCXy/Hqq69O7suug/moWPYCy33Pu9xt9Y7pdv0qLcAASt08LKXsBxBC3A2cDNw324M+LOARS7k0t+MIEGAGcNJJJ3HiiSeyfv16fvrTn/I3f/M3XHfddViWxRVXXMHatWu56aabuOqqq7j11lvRNI1vfvObnHnmmVx55ZWcfvrpAHz4wx+umJSOP/54MpkMy5YtY8mSJQBceOGFbNmypWJCSiaT/OQnP0HTtJrxjHXcySefzOWXX87atWtZuHAhp5122oSfbcGCBVx66aV8/etfB+Dkk08ec8weHnzwQa6//nrC4TDJZJIf//jHdHZ28sMf/pD3ve99FfPgddddx+rVq6f0nXsQUsppnWCm4RLFq8D5KAJ5Cni/lHKz75iPASdIKf/add6/R0r5v4QQbSgSOQswgd8CX5dS3jXee5566qkyaPQF3Hoh7NkIn3gWOt4w16MJcIhhy5YtHHvssXM9jACzhHq/rxDiGSnlqSOPnXeKxfWZfBz4HaAB35dSbhZC/DPwtJTyV8CtwH8KIbYDg8AV7muHhBA3oMhIAndPRCoBfPA77wMECBBgiph3xAIgpbwbuHvEti/4HheBy0a+zt33E1TIcYDJouK8D4glQIAAU8fh5rwPMB1UfCwBsQQIEGDqCIglQBWBKSxAgAAzgIBYAlRRk8cSIECAAFNDQCwBqvDCjIM8lgABAkwDAbEEqMIjlCCPJcAhjDvvvBMhRKXQ5Hi48cYbyefzU36vH/7wh3z84x+vuz0UCvHiiy9Wtq1Zs4Zdu3aNe763ve1th2Sp/5EIiCVABTLwsQQ4DLB+/XrOOuushsqUTJdYxkNXVxdf+tKXJvWau+++m9bW1lkZz8FEQCwBKpDlgFgCHNrIZrM8+uij3Hrrrdx2222V7bZt86lPfYo1a9Zw4okn8o1vfIObb76Zffv2cd5553HeeecBtY2zNmzYwJVXXgnAr3/9a970pjdx0kkn8Sd/8if09PRMOJZ3vOMdbN68uW4Z/PXr13PCCSewZs0arrnmmsr2lStX0t/fTy6X4+1vfztr165lzZo13H777YCqYnzuuedyyimncNFFF7F///4pfU+zjXmZxxJgDuDYhLDV44BYAkwX//MZOPDSzJ5z8Qnw1i+Pe8gvf/lLLr74YlavXk1HRwfPPPMMp5xyCt/5znfYtWsXzz//PLquMzg4SHt7OzfccAMPPPAACxYsGPe8Z511Fk888QRCCL73ve/x1a9+dcKGW6FQiH/8x3/kX//1X/nRj35U2b5v3z6uueYannnmGdra2rjwwgu58847efe731055re//S1Lly7lrrtUfncqlcKyLD7xiU/wy1/+ks7OTm6//XY+97nP8f3vf3+ib+6gI1AsART8DvsgjyXAIYr169dzxRVXAHDFFVdUzGH33nsvH/nIR9B1tZZub2+f1Hm7u7u56KKLOOGEE7j++uvZvHnzxC8C3v/+9/PEE0+wc+fOyrannnqKt7zlLXR2dqLrOh/4wAd4+OGHa153wgkn8Pvf/55rrrmGRx55hJaWFrZu3cqmTZu44IILWLduHddddx3d3d2T+hwHC4FiCaDgCzG2yyW0cQ4NEGBCTKAsZgODg4Pcf//9vPTSSwghsG0bIQTXX399w+dQbZ0UisVi5fEnPvEJrr76ai655BIefPBBvvjFLzZ0Pl3X+Yd/+Ae+8pWvNDwGgNWrV/Pss89y99138/nPf57zzz+fSy+9lOOPP57HH398UueaCwSKJYCCT7HYVnGcAwMEmJ/YsGEDf/7nf87rr7/Orl272LNnD6tWreKRRx7hggsuqCkz77X2bWpqIpPJVM6xaNEitmzZguM43HHHHZXtqVSKZcuWAdSYtRrBlVdeyb333ktfXx8Ap59+Og899BD9/f3Yts369es599xza16zb98+4vE4f/Znf8anP/1pnn32WY455hj6+voqxGJZVsPK6WAjIJYACj6/imMFprAAhx7Wr1/PpZdeWrPtve99L+vXr+fDH/4wK1as4MQTT2Tt2rX87Gc/A1TL4osvvrjivP/yl7/MO97xDt785jdXyuKD6m9/2WWXccopp0zojxmJSCRS6T4JsGTJEr785S9z3nnnsXbtWk455RTe9a531bzmpZde4vTTT2fdunVce+21fP7znycSibBhwwauueYa1q5dy7p163jssccm/T0dDMy7svlzgaBsPjC0C25aC0Du9E+SeNu/zO14AhxyCMrmH96YTNn8QLEEUPCZwpzAeR8gQIBpICCWAAo1prAg8z5AgABTR0AsARR8ZVxkoFgCTBGBaf3wxGR/14BYAij4TGEyqBUWYAowDIOBgYGAXA4zSCkZGBjAMIyGXxPksQRQ8JnCZJB5H2AK6Orqoru7uxJWG+DwgWEYdHV1NXx8QCwBFPzEEiiWAFNAOBxm1apVcz2MAPMAgSksgEJQ0iVAgAAzhIBYAii4iiUvo0GjrwABAkwLAbEEUHCJJYcRtCYOECDAtBAQSwAFj1ikgXACxRIgQICpIyCWAAo1iiXwsQQIEGDqCIglAFBNiswSQwTEMgr3bD7Ai92Hfi/yAAEOBgJiCQCAXa4670NOQCwj8S93vcx3Ht4x18MIEOCQwLwkFiHExUKIrUKI7UKIz9TZHxVC3O7u3yiEWDli/wohRFYI8amDNeZDHV59sBwxQoGPZRQKpk2uVJ7rYQQIcEhg3hGLEEIDbgHeChwHvE8IcdyIwz4EDEkpjwK+Doxsz3YD8D+zPdbDCbZHLNIgFJjCRqFg2uRMe66HESDAIYF5RyzA6cB2KeUOKaUJ3Aa8a8Qx7wK8Nm4bgPOF21NUCPFuYCcwP1urzVM45RK2FBSIEJKBYvFDSknBssmbgWIJEKARzEdiWQbs8T3vdrfVPUZKWQZSQIcQIglcA1w70ZsIIa4SQjwthHg6qG2kerBY6FjoaIEprAam7eBIyJcCxRIgQCOYj8QyHXwR+LqUMjvRgVLK70gpT5VSntrZ2Tn7I5vnkGUTkzAmOlqgWGpQcE1g2cDHEiBAQ5iPRSj3Ast9z7vcbfWO6RZC6EALMAC8CfhTIcRXgVbAEUIUpZT/d/aHfWjDKZuUPcUiy+A4EDrc1h1TQ8FSxJIPfCwHD4//B3Q/CZf9cK5HEmAKmI/E8hRwtBBiFYpArgDeP+KYXwF/CTwO/Clwv1RNIM72DhBCfBHIBqTSGKRrCjNlWG1wLAhF53ZQ8wSeYsmZZaSUuO68ALOJ7idh16NzPYoAU8S8W5K6PpOPA78DtgA/l1JuFkL8sxDiEvewW1E+le3A1cCokOQAk4Msl7CkhumtNYLS+RV4ikXK6uMAswwzr/4CHJKYj4oFKeXdwN0jtn3B97gIXDbBOb44K4M7XGG7isW7JIIKxxUUfWSSK9nEI/Pytjm8YOXVX2CSPSQR/GIBANU10nR9LEBQ4diHgulUHgchxwcJZg6QUC7M9UgCTAEBsQRQsN2oMM/HEiRJVuA3fwWRYQcJlmsGC8xhhyQCYgmgYFtKregR9TzoIlmBn1jma2RY2XZwHDnXw5g5eIRiTpg5EGAeIiCWAAq2iSV1Qnq08jyAQtH0+1jmp2L52C3/zbd++/RcD2PmYOXc/7OoWAZem5MFlO1I7tvSgwpkPTwREEsAAIRtYqGhhV3FEvhYKiiMcN7PR/zvwc+xZtt/zPUwZg7mLJvCyiX45h/BYzfNzvnHwYNbe/nQj55m0970QX/vg4WAWAIAIGxLZd2HDbUhiAqroIZY5qHzXkpJh0xhWENzPZSZgeNUnfazZQorDKv32H7f7Jx/HOweVGSZKR6+91hALAEAEI7ysegR1xQW5LFUUPCZwvLz0BRmlm1iFNEOF5XpN3/Nlims5KqF7qegdHD9OPuG8pwuthzWOVEBsQQAQDgqKqxCLIFiqaBo2WghlW0/H0vn53M5NCHR7eJcD2Vm4CcTMzc771F0icUpw+4nZuc9xkDrvkf4efRfCPdtOqjvezAREEsAAEKuYglHPFPYYbL6nQEULJtmQyesiXnpvC/k1SQZduYBsaT3gTNN8vWTyWwRS8nn39j54Oy8xxiIpFQnUid/mJgu6yAglgCAIhZTakQiMbUhiAqroGDaxMIa8Yg+L8ONi7kMMA+IpZSBm0+GF9ZP7zwHQ7F4xBLvgB0Pzc57jIFEQdXUdUqz9NnmAQJiCQD4FEvU87EcmsSSLZW547nuGT1n3rIxIhqJiDYvFUspr4glIudYZRaGlEO8/9Xpncc8CD4WzxR2zNvgwEuQH5yd9xmBUtmmzeoBwLYO36oCAbEEAEBzLMoijFYxhR2axHLXi/v4+9tfoHto5iakoqtYElF9XkaFecQSnWti8Zzg6f3TO491EE1hx14CSNj1yOy8zwj0pEosE/0AyFJALAEOJ+x+AnY8WLMpJC1soaO5mffOIRoVNpxXQQczabIqWK4pLKrPyzwWqzBPiMUjgcw0icU8iM77I8+FcAJ2Pjw77zMCe4cLVWKZzeTPOUZALP8v4oF/hXu/WH0uJbq0sEORSh7LoUosmaJSFMUZDOUsWDYx1xQ2H4tQlouKWAzmmljUOEjvm955Dla4caQJ9Cgc8eaD5mfp6R+gQ7jfU0AsAQ4rFIdrV4KOmiwdEUYLKx9L2To0iSXtJp0VLWeCIxuH33mfnYeKxS4qE1RMmFjlOSQ+v2KZTrkS7zzhxOwlSJbSYDSrx0eeCwPbpk+IDSDbs7PyWAQ+lgCHFYrpWmJx/SlOqEosziFKLLOhWIqWzZ+mfsC5xfvmpWLxRxcVC3MYaeT5WKx8bTjvZOGt5JOds1fSpZiGqEssq85V/w+COcwafL3yWBzGLQECYjmc0fNyfUdqaQSxuGYvJ6Sj62EcKXCsQ9N5ny54imVmTWGnp+/hpPxj89LHUkMs+TmsBuxXF9Nx4HvXZqJzdk1h0Sb1eNEaiLUfHHNYak/loSjPg7yjWUJALIcrpIT/fDfcf93o7aMUi5qMZShCJKzaEx+qiqViCivPrCks4pSIycK8DDf2R1GZc6lY/MSSmYZZycqDCKnJfrZMYUWfKSwUgpVnqciwWa44bOT2UkZnWLSi2YFiCXCoYeA1yPZArrd2u1UAx1J/Xq6KawqToTBhTShiacR53/cq/NsKGNo1s2OfBmbHFOYQlkViskDBsrHnWd8T4VskmMW5JBbfe09LseSVfyUSnz1TWCmNE2mqlq5fdY5SE0M7x3/dNCClpLm0n3RkEaVQDO1wKcFTBwGxHK7Y/bj6Xxiu3e63fXsrXY9YtAhRPYRJuDFiGXwNSino3z4DA54ZzLQprGw7WHaZsFMiKtUKc74VDxQ+c5FVmENTWCkLmptgO52QYyunSCWSmLVwY1lMc8eWLD/duFttqPhZZi+fJVWwWCz7KCaWYoWi6HNdKWEWERDL4Yo9bmG94ghiKfqIxVsNeqYwLUJED2GhIxvJvPeiWkqpaQ525jDTiqVYdoiivp+Ia7qYb+YwrewjljlVLFmIt4PROj1iMfPYeoyUHalNlpxJlDL0WVH++1m3SsOCoyG5aFYd+F4Oi9PcRTlkHD5FQ+sgIJbDFV7F1uKISb9GsXjE4jeFhTCljmxEsXjHFOdHwyLbkWRKHrHMjI+lYNrE3PyQiK2+r/lGLLpdJZbyXNafMrNKZTQvnZ4pzMrTW9T4zSvp2VEstoUoF8jKGM/tGaY3UwQhlDls58Oz5mfZP5BmIcPo7SspazEizqHpx2wEAbEcjsj2wcB20GOjTWF+BeM5Rr3yLVqEiKYUS0MlXbxwyemEls4gsr4Jf8YUi2UTQ30X3gQ+3wpR6naBMhoAtjmHDmEzB5EkNC2ZnvPezJGXUYYsXeVYzXTdOnchlCGOlHDfFtcPueoc5ZOcbq2zMZDp2UlISOILV2HrBuG5rpQwiwiIZRroTRfpTc9DObtno/p/5Lmq/L3lG2NdU5hHLGEiro+lEVNY/7BSQ6nhgZkY9bTh+VdgBhWLZRMTagLQ7CIadg2BzQdE7Dwp0QKAXZrDbG6PWJqXTFuxFITBcNltkz3T5jDXdJuRqpL3PZsPqO2rzlH/Z8kcVujfBUBy4UoczZj7EjyziIBYpoErvvsE1/7m5bkexmjsflw5UY98i3ruVyl+dWHWOu/RIsoUhtaQYhlKqdIUmeGDUxl2Inj+FYBieWZURcG0Mah+F3FK8y5JMuwUyWqKWJzZiqJqBKUMRJPQtFSt/O0pfk9mnryMknHcQICZNof5FMubVrXzh+0DarHQthJaVsDO2clnkcMqhyXUtgKpK2KRUzC7feK7/8NPH56H844PAbFMA81GuGaVPG+wZyMsO1klmEGtOaxYLypMfQahq6iwRk1h0nXey5F+nDlCuuhXLDNELFbVxwKQoDDvkiQNWaAYaQPAmXPFkoCmxSCd0aHujcLKkZMRCtIjlhn+TKUqsbz35C5M2+GhrX1q36pzYNej4MxcHpSHcKYbhxA0L0PqcQxRojSFfKtPd/8ti567acbHN5OYl8QihLhYCLFVCLFdCPGZOvujQojb3f0bhRAr3e0XCCGeEUK85P7/49kcZ3MsTLo4v1avmHnY9zysOANirWqbf+L3P66jWCJ6CFOGEY34WKz55WPxK5bSTDrvRfW7SIjivHPeG7KEGe1QT8pzSSxZ1xS2VD2fqjnMzJNzouTwiGWGQ6g9xSLjvOWYTtoTEe552WcOKwxBz8y3DU4U9pPWO0CPIMMxYpgUpuCv62CYlsLuGR/fTGLeEYsQQgNuAd4KHAe8Twhx3IjDPgQMSSmPAr4OfMXd3g+8U0p5AvCXwH/O5libDZ3MfFMs+55VyY/Lz1Bhn1DHFKb6t4/0sQg9Sth13jdCLF7kWKiUmanRTwueemwy9BnLNRmtWIoN9b3Plcoz2hNmLFi2Q5wittGuNswX5z1M3YFv5ck4EfIYleczCvd6zRCjORbm/Dcu5P5XejHLDqw6Wx0zw34Wy3boKB8gF1OkK8IxYpQoTNKsWi4r02zS6p/R8c005h2xAKcD26WUO6SUJnAb8K4Rx7wL+JH7eANwvhBCSCmfk1J6V/NmICaEiM7WQJVimWfE4oUZLz+9SiwjTWGeicxbCZY9YnEVCzrCaeBzuVFhujVfFIsac2dTdOZMYSN8LAlRJN+AYvnG/dt5xzcexbJn3qTiR75UJk4RIgnyMjp3isVx1PUUnaZikRLMnCIWOUs+FldhF0NxonqIC49fTKZYZuPOATX25mVTVyw9L8Mfbh69OV1kGf2Um5YBICJxNCEpliYX/FM0S2hC0mIPTW18BwnzkViWAXt8z7vdbXWPkVKWgRTQMeKY9wLPSlk/9EIIcZUQ4mkhxNN9fX1TGqjysZSn5ICbNex+AjqPVYlq9UxhpbRKBEOMymMJaVViCTWgWLwieuHyHGZ7++CZJTuTM0gslo3hM4W1aKWGFMv23gzDeYst+2eXdPOFPLpwENEkJREhNFeFDb1rKZKA+AII6VNLkiwXAUnaDlcVyyw574m2IITg7KMXEAtr3LNZtQwm1lZRNZPF0OM/ht//H+jfVrN932COxWIQ0XYEoIgFoDTJSgkltxZchxyiPEMBKrOB+Ugs04YQ4niUeewjYx0jpfyOlPJUKeWpnZ2dU3qf5piOaTtTcsBNCUO7YOtv4cnvwgP/BpkDtfulhO6nlFoBMFSkUI0prJhW2yPJUT4WEVZ5LCZhhNMIsSjOjs4TYskULWJhjSZDn7FwY38eC0CbbjbkY+keUmruqV2zu7Is5NQkGYomKBElNFel2F31uysjKJQlJBdPjVhc82zWiVLwfCzTMYU5Njz9/VpyKqUwRRTDUMRlhDXOPnoB927pUYvESHLKfsNde5XBpGfjL2q279m9g7CwiXWuBEBziWWylRKKeXV8VJQZGpzagvhgYD4Sy15gue95l7ut7jFCCB1oAQbc513AHcBfSClfm82BNhthgIMTGfbqPXDzSbD+crj7U/DQl+H5n9Uek+1VJLLoePVcC6tifiOd90azW+CvNipM01W4sSV1Qg2YwkJuSQrDyc16VdhGkC6UaTJ0omFtRsON/T6Wdt2csO+9lLJKLDtnNxTb63evRZOUQsYcEou6lm56ZD+3P7XbzWWZgo/FjVTMEyU3E6aw7ffBb/4eXrmruq2YJh9KkIzqlU0XHLeI/akim/a65fRLU1ss6aa618qbf1mz/cnnngNgwbKjANCiilgmW43a8lVWSPXtGefIucV8JJangKOFEKuEEBHgCuBXI475Fco5D/CnwP1SSimEaAXuAj4jpfzDbA+0OeYSy2z7WbK98MuPKhPXh+6Ff9iqHKQj5DYD7vOOo6rbjJZaH0sppRocRRKVlaDj+lhCYQMtJLDE5IhFw5m93uSTQKZk0RwLEwtrMxcVZtkkQn5TmEl+gnDjVMEiWyoTEvD064Ozaiot5VxiiSUxRXTu6k+5pqOcjLJ3uOBm309dsRRkdGZMYdt/r/77+qBQSpMjTpNRJZbzj11ESKCiw6JNUzaF6ZZ63bL8KxTdhMgX9gwTH1A+G9G2Uh0XTQCTVyxWsare8gPTSEKdZcw7Yo8Z7hsAACAASURBVHF9Jh8HfgdsAX4updwshPhnIcQl7mG3Ah1CiO3A1YAXkvxx4CjgC0KI592/hbM11mb3wkwVZjH8VEr45ceUCeu934Plp6k8gQWroX9r7bEe0SxYXd0Wa61jCmt2276qi9p2e6+EdLd7pAijyYlNYTV+mBkMOc6b5QmTEDftTfHbTbWmQE+xGOHQjPpYkpoFuprkmkPFCRWLp1bOPrqT/qzJroHZc6ibBTWRhY0mrJCBNlcVc91rKUuMnnRp6vXCfIqlRFjlfUyLWO5V/1Pd1W2lDFliNcTSnohw6sp2fv9yjwpAmCKxGOU0O6WKitv24HoAfvbYNq7S78Zedhp0vAGAsKEUy2Rru/mJpTQ8+62Up4p5RywAUsq7pZSrpZRvkFJ+yd32BSnlr9zHRSnlZVLKo6SUp0spd7jbr5NSJqSU63x/U8zSmhgHRbE8+V3Ydg9ceB0s8kVdL1it+qH4V8P921R9sGZfrIPRWjWFSQmlNL2WQVZGfMTiKg9dfR47FEFrQLHo/iJ6M1iI8u9ue56/ve35uvscR/Ldh3fw7lv+wEd/+kxN1FWmaNEc1WkWxRmtFZYMWUrhhRM0axP7WLww4/ecrH6Hp3bNnjnMcvvdR+NJyiGD8BwTS14a9KSLSrGYmYkn6FR3LQG5ikWpFUFZi03dxzLwGgzuqL6Ph2KatIzXmMIALjxuEa8cyKhSL1PMnTHKWfYn3sh2sZLwq79hOG8S3/RTlogBtD/+nCp2CeiGUizl4uRMl1apenw5fWCcI+cW85JYDhXMuo9leA/c83k4+kI4/a9q93Ueo25cvwN/YJsyg4V8P6vfFGZmQTrct6PAtiFZmQycsokpNSJht5ChCKNJa0K/iWYXK/WWppJ9/+5b/sDN920btX1rT4atB0ZPSEM5kw//+Gm+dPcWFjZFcST0Zqrkli6WeZP9DH//wtuJWKkZMUEVTJtkyISw6g+SFIUJi1B6iuXc1Z20xcOz6mex3aiiSKyJsjaXxKJ+ryyG+k0quSwTTH53/DX8+m+rz62qKQzADMWmrli236f+LzxuhGJJk3IMmtz718MFxy0CYFtKqHvFmfziJO5kscIt9C+/kNWlzfzgNw/xkdCd5BafXi2xBESMJAD2JD+b7atCEMr2THp8BwsBsUwDzTG14pm17Ptdj6oikhf8c2WlU4Fn7vKbw/q3qb4SfsR8isVVFQO2q1gqPpYSFjphTV0OjhYhhJzwxtKlSZ9UkWdWfnjcY0dCSsnL+9K8sGd41PYDqSL7UwWcEZ0ab7z3VR5+tY9rLzmeL73nBAD2D1dXcJmixQr2E3ZKtJHGsmeAWCybuDAhHINokgSlCYtQdg8VaIrqtMTCnHJEO0+/PnuRYbbrZDYSLdiaMXul2B0Hup8Ze79PsfSmi8p5DxM78DMHYNiXRW5WTWEApZAxDWK5F9pWud0hq8Qii2mGnBhJo1axHNGRYPWiJJv63et+sqpFSpLksKPNHHnO+wgJyfmbPs1iMUTiov9Tcw9H44pYJlvbrexLgNULQVTYYYlZVywHXlKmLb/PxIO3rc8t8V0uwfDro4nFaKn6WFw/yIBlkHWilRtHlq0aYpEhdyVnjz9JhZ0SfahcmUJmcpNnplTGtB32p2pX2MN5i1LZwbIl/dna99/el+WErhb+8s0rWdqilJL/9elCmRahJiEDc0YiwwqWUyWWSIIEjSiWPMvaYgghOH1VGzv7c/RlZmfCd0pVU5ijGURmq2Luzofge38Mr91ff787jiwGOdMmF3VdmxM58EsZ1ULbg+WZwlxiEcbUTGFWUWXPH32BMg2X0tUFVilNyqn1sXi48LjFvOwV656sn6WUQcNBGi0sfMNJHNCXcWJoJ30LTq9WTnYRdU1hcpLE4rjEkiGOUQyI5bCEEdaI6KHZ87EceFGFDoe00fuaFqvoLq93xOAOVfivYySxtKqbyrEriqXXMsg4kYo92ymXMFH97gHsCrGM78AP+xRLKTs5YhnMqnPvT9XamA/42hDsHa7d1z1UoKtNOT2XtCpn+gGXWIqWjWk7NKFeY2DOiJ+laLp5LOE4RJowmLhWmBqnIr5TV6pSK0/Pkp9Fuqv5SKwJR48RZZaIJedOYi/+ov7+itJQv0sPbomZiRRLKQ2FwWrPFV9UmBBQFEatctjyG/jOWyYOB979mKoMcdSfQEuX2pbqBsdGmFkyMk5TdDSxXHDcoop5d7Ihx0X3HhBGKwiBPFbFGrW89Qujjg25eSzjEcsLe4ZH1RLzFE6vtphkeX5UFa+HgFimCS/7ftJwnPEd3lIqYllyYv39QtRGhlUiwuqYwkCt1twVW68ZIWVHK5OBLJuY6EQ8xaK5fTAm6MkSlib9Up3fzE3OxzKQUxPgUN6qIYADPgWyb7j62HYk+4arE3ZTVCcR0SqKxSP3pHRX8MKakZBjlXlfqiiWmFOgVHYoj1GqRUrJXh8BrlnaghEOzV6ipGcmiiSR4RhGA9F846JsQs/m0du9qL9XflPb36cyjgxlEaGMmqwPFELKz9K3dfSxHmyrqkY84vJFhbXHIxQwaqsb73oE9j2nkh7Hw7Z7VeuIlWdBi5sWl+quqJAso01hACcsa0G4/o/JKpZ8StXvCsVVpeklb/8sfGADkTecPfrgsEteVn3nfSpv8Z5vPsaGZ7trtnuKJW0so9UOiOWwRXNMH1+xlDL1wy6f+zHcuGbsyXt4tyKCxSeMfW4vMgyqysWfwwK12ffu5DBoG+RkRK3oHBtpl7Ck5jOFucQynmJxbMKUMSOtlGWI8iR9LP3Z6rn95iy/YtnnUyw96SKWLSvEIoRgcYtRUTxeZeOE9JnCxlEsj23vb6iOV8GyMWRJKZZokqjj9r0fwxyWLpTJlMqVcUb0EOuWt/L067M0CZh51T1Sj4AeIyos5FT7oAA8fD18+9zRq3Vvki2lVZTiqHHkMLVY5WlvugSLT1SLo7Hgn7i9EvsuiRSJsCDpVjj2+1g8X8lj3xhzUgaUf+WIN6tovopi2VO5B9LEaYqGR70sFBKEYy3VzzoJFDLqNw4n3MWc0aJMcfXgEosYI6G1N1PEdiTDuRH3oFuyp5jsooUsjjkPGw0SEMu0MWFPlvv+Bb5/0ejt3U8p4hjr4j3wkvq/eO3Y5+5cDdkD6jwD25UtOZqsPcYYrVjSMk5O+irHlk3lY9FH+ljGIRb3ptaNOFliOIVJKhY/sfgIZH+qiBAQC2s1pjAv0mq5qwQAlrTEqorF/Q0M23VmY45Z1mVnf473f28j922ZOKqmYNrKvOQqlojjrqjHyGXZ44Yae8QCcPKKNjbvS89KQUqtnFOreqhMVqVJJt1V4Njw3E9UdezCCIVVyoLQVAHTl+qYw0pZSqE4Efca6kkXldru2zo2AfgjCbMusVh5rJCBJERHMqKy760RxJJYqIjomR9RF8O7lZI/6k/U8+QiCIXVa30l8+spFkAlSMKknfcll1giyfaJD9bCqor4GLXdvIVXfsTiSLqKRbauBCAzOD9zWQJimQ6yvSyPpMePChvcoZzqI29Uz3Q1ltw+8CKIECw8duxzVyLDtqm/EWrlzuf2sjXl/sSFYd9qLVGtw2TmkbbnvHejVtxEyXGJxa0TFonGycj4pFd3g7mqL8CvWHpSRRYko3S1xWoUS3edCXtJi1ExnXmKJVpW32eM0pjOe8+Rnmog6KJg2aqFbDgGkSbCtqtYxvCzeATY5SfA1hi2IxnKz3DvdiBULqjIKaqFDYu5KdZu2/FAtdT9yOvS6w55/KXw6u9Gm3HNLEVh0JmMEo9oKuR48Qkgbegdo9uh/z08B76ZwwzFiOghklGdnBOtNYWl98IxF8OKN8MfbqpchzXwTHnL36T+h0IqYTPV7WvyFRuVx+IhZDTV/w4mgJlT97jR1ACxACURHVOxDGZy3BK+kfahl2p3lAs4UhBqU+a99Dwt6xIQy3Twg7dxZepb4/dk8W4Yz2TlwSOWsUIpD7ykHPGReP39AAuOcc+9dVSose1I/vcdL7HhZXeSKQ5DMYUTClMi7FMsObCVYvF8LEJrQLG4N4QRS5AhjpgksfRnTYywej+/A/9AusiSFoOlrTH2+bbvGVSPl7bWEktvpkjZdirmSK+khiGsMZsoDbsTfCOFKgumTdgpVfJY9HIOkGN2kaxHgO1xZVocyk0/yOMHf9jJnsHqRKuX8yrXgyqxmMUpEstzP60+Hvl7ljIqWGTNn6poQX/tLQAzS96drBc1u0mSi13/4P4xzGH+9/DuEyuPGTKIRzQSUd0NMnHvkXJJ+WJalsO5n1Yk+NxPRp/Xi0TzQp5BvWaEYmk2RpvCAEKx5upnngTKLrHEmxsjFktE0Oz6xFIY2MvbtSdZNvxUzXZRLlISEWJtqjVBbp6WdQmIZTqId9BKZnwfiyfx/fkmuQEVCQPjE8tYjnsPbSuVxH/9D6oGmC8seVtvhrxp02O6BFJMQTGNHW4CRCWcEzMHtkWJcNXHorn7xnPeuw5c3YiTFXE0c3I34UDOZHGzQVs8XOtjSRVZ1KyIZb/Ped89lGdRcxQjXI2QW9wSqyRJeopFN9XEMZ6PxVMqEzUDk1JSsGyVdOjmsQjpEMUas6xL91CBpJvD4qE9oYhlcKS9fJJIFSyu/fXL3P5UdZUatvNYLrGEKqXYp2AKKwwpslh6sno+SrG4xRmXn676wm/aULvfzJHHIB7VWNgUVT6WtpUQbRnbz+JXPd59YuYoCYNYWCMW0UjbVV8gabcWbfMyOPI8WHYqPHojjPQpZVySSi6qbmvpqlEsYznvASJxj1gmR9BOYQhHCpItIzt41IcpDLQxarsVUyqxVIwItRZ2iRIREguU38icp2VdAmKZDuIdNDmpsXuyOHY12sUfHTPgyzavZ8fNDypH43iOewBNV7WHtv6Peu4zhT2/WznT95dcknBNYZaufDB+U5iwzRrnvdAndt5LV7EI3aAYSlSUQqMYzJW41r6ZK42HRznvl7QYLGs1GMhVycEfauzBCznenyqSLlgInIpyUnks9RWJRywThSOXyg4aNrq0XMWivrskhTELUXqhxsKXDDdjxJJX4/b7nsJOAUtT38tUS7EDsOm/lBI542/U85GVFMysIhYhYM174LUHIOfrYmjmyGFUFUumqI5dfMLEikWL1CiWIlFiEY1ERFPRi+72iuO+ZZk69ylXQmq3aifhR/aA6gmj+RRJS5cKfXZN0pk6JV08xA2DogxPvv5dIU2WGM2xxnoLWqGxi4aW02reGFmtWpSLmCJCW+dSHClw5mlZl4BYpoN4O/FyauyeLPkBZWOGWmLpn4BYKo77CRQLKJXiqR+fKeyFbkUsPQVNNV0qDkMxTUlX9uOKKczMVk1hruO16mMZOyfCdp2IImxQ0pJEJtmTZSBT4szSo/wRz1eIpWDapApWRbFANTKsezhfY14CZQoDpXIyxTLNoohAEXxUjK1YhvMesYxvCqvpHhmOVYglLsYuRNk9NHqcbQk1wQ1O08cyXFCv3ztUnWyiTpGy7hLLFCvmAsoMtmiNCs+FMXwsru/hje9Q17XXrRSglCXjRElEdBY1R+lJF9Via8mJyudRr4qDp1jaj4SsuwAz8xSEMoXFIjppO1zZTspTLG6Ul9s0a1QL5MyBakkZDy1dasxu9GRJT1av9xFIRsNkiOFMsv5dqDRMikTFxDsRxivBI90oOW1ER1DNLmGJCG3JOIM0IbJjlEJ87idKzc0RGiYWIURiNgdySCLeQcwaBmT9yDB3FVYSxojSKz5/Sz1TmGc6mEixgKoZBm7xya7K5udcxZIqlt3sexWBVtTUz+hvoiScET6WimIZ28TnVVkNReKYelL1ZJkECtlhItJkIUMVH4sXary4hliUD2XfcHE0sTR72fcF0kWLJdHqxG1gUhqLWAqej2V8xVLwN/lyo8IAEpTq+lhG5rB4aHN9LIPZaRJLHcUSlQUcXX0PYa+w4SQr5tK7BfY9C+ver/woUN/H4hIr7avUf880BWBmSTtR1xRmULQcFdSy+ERlyhrZ4sH/Hh1H+RRLjryMEg/rxCNatT2xlYO0T7FAtdhqyjcOcIllUe02L5eldwtloROJ1l5LfiQNnayMUS5MToVrZpqcSNSo1fFQDsWU/67euQoq/X+kD0ZzilgiSigkGBRthMfKvn/yuyoke44wGcWyTQjxUbexVgCAeAeatEhQrO9ncW+WjfYxyOE9VRIZ2O7rO1+PWF6CpqWQWDDxGDy/iq/4ZN4s82pPhoimqgJIo1WZwoop8u76IOfrdSFsCxOdsK5uiFDFxzK2YjHdKquhiIEdaSI2iWZfjiPRC8qM0moPMJxXjnaPYJQprKpYDqRVTP/yERN2c0xNPvtdxbLYqI53vHDjqmKZmFgM4Z7Tdd4DblmX0YqlJoclP1hRnmEtRLOhTzsqzDPh7U8VsGwHx5HEKOKE1bi8irn2ZIlly68BASf8L/UZRWh01JdfscQ7VBsBf48TM0vKjpKM6ixsVtdPrxdyDPX9LKW0MoO1rvD5WPLkZdUU5r9OSe1V7+0lF3qqJF2PWBbXbvNyWXo2UwwlSI7huAeVfJsjhj1JxRKx0uS1poaPd/SxS/BEiopYwiOIRbdLlEPq+03rHcTqEYtjKwtJvr/6vR5kTIZYLgTeCrwihLhilsZzaCGunHRtIlO/J4v7oz5mH6tMNN6qrX8bLFmnHo9lCpvIce/BI5YFVf/KS90pHAmnrWpDSrCjLRXnfU6oyTnv684XcmprhYXCE/tYyiWlWPRwHCfSNKlmX6mCRYdUtu6k2QdI9qcKKpIIOGb791jy0jcRQq3O64XwQjVJ8oDrY1mo+4nFmrbzvmCOUCzuxJoQxbqFKLuHfRFhD18Pt15YyeFoT0Sm7WMZzpf4kn4rx7ODA6miKpCJG7EGRGIesUyytlauX/XoSXYq30W9RldeVBioY5qXVX0eZRNsk5QdIeH6WMCtPL1gtcqA3//C6PctptU5kwtVdWQzB1aerIxUTGF+XyCp7tqWEJG46k/vLxvj2CrHJamIJV20uOrHT9PtuJFaxWFyIjGqsrEfSUMnSww5WWIpZyhpyYkPdGFrsTGJJW6p+2OkqUx3qsRSiHTUL+sytKsStVm3isJBQMPEIqXcJKV8J/BB4G+FEM8KIS6cvaEdAnCJpX2syDBXsTzuuH1U+l9V5qWhncrMJUKjI0+sglptNGIGA+VX0aLVdsRU/SvnHK1UkRVuqmTep0nQFg/XdOcTjoUpq1FhoQbyWDxi0aIxNSlBw87OgVyJBUI5h0OyTBsZt6Kxuonatt+Bvvm/WNgUZV8NsYw2Xyxxs+8zxTKdkerqLibGLkLZqPNe9bsfrVjaNLNuIcoaAhzcoRzOux8HZoZYSpkBPqDfx9u1J+geKpAzy8QpVkxUUWOKxOInDVCRXP7f0nGqznsPXpQVVBZHaafqvAc3SVILqz5CYykWo1klPIJaiJl5so5Psfh9gem9VZOWh+ZltcSS61c181zF8tDWPu55uYdHdhcrycK5cXJYAJoMnYyMIScZFRazs5T05okPdCF1A0OWRlXxLlo2LY66h71KDx50p4Stqe+kZHTS6gyNthT0bvE9HpFD1P2Myv+ZZUzaeS+lfFhKeSZwHfAtIcR9QojTZn5ohwA8YhGZuj6W0vB+MjLGy3IljtAUYQztAqesVnKRptGr/N4tysnYiOMe1GT3kYfgjI9WNj2/Z5jl7TFWLVATTUlvVqaZUoa0jNEaj2DrXq2ivKtYtIqPJRRWxOJ1lqwH2zWFaRED4ZaNabQnS3/WpFNUj10khtmXKtKTKtJkaITS3ZDZV8ll2TOYR4hqFJgfi5tjSrEULTo0d3UXjpMIWQ2YwiZw3o/ysagJvC1cv9lXDQF6k65bDXgmiMXMKPPIEaKHvcMF8vkCEWEjXKd92FUscrLVgL1QYg8jFYunqv1VHVqWV30b7jWcQzndFzap66cn7V4/i09UkWEjJ0CP0Lyw4GwvWDkyjqdYtBpfIKm9Vf+Kh+ZltaYwL4fFJZYndqjvrHsoXyGlDONk3YNKzMRATDKEPuFkKUcmQSzhGIYYncg7kDPpEIrYo7JWsYRlCds1VduJhYQpj06+9ojFaIGeEcTy2M3w+y+MXw5nBjAZ5/0iIcRbhRCfE0L8F3ADsBRoBjYIIX4qhGgsM+hwQVx93DYydbPvi0P76JMtWOikjC7oe6XquF9wtCKFkaYwL3RyZM2v8bDw2MpqGuCFPSnWLW+r5FIUQkn35pMMu+XCY5EwplCl8zXXee9l3nuKZVxiMb2SLgk0t7aSmW2sXthgzqRTVI9dJIY4kCqwP1XkqGZbfSeFIY5oDrFvuEj3UIHFzQZRfXSV56WtBj2ZEsN5i7aQe7MkFxELWWOaurwEyYZMYTU+FjWxtmqlMYglX81h8fwPrz0IKGKZro/FS8A7QvTSPZSnkFeTT8glFiPmTvzmJCcNv/8ElIrwLxI8kqlRLMvUJG5blWs4J2MkojqJqE5TVK+YNllyolLMqRFZ4kWX0JKuYkl3g1MmbYeJR9R5Kj6WzAGVq9U8kliW1ioWLwjANYVtdJusdQ8VKn6WsUrme2hynffaZEq62Jbyd0VbGn9NOEasji+wP1OqEIshizWKJiJNHFexhJrVZ8wPjvAx9b6scoiWngQ9m6rbpYQ9G9XjwZ2Nj3MKmIxi2Qt8FdVT/j7gMqBZSnmau20X8N8zPcB5jQkUi5PuqfQr2R9eoUjF87N0HOUSywjF4pkgjElcoD70ZorsHS6wtquFlrgillwoWTFrDdnKXBGP6JghVTk2JJWPRQspYtEikyCWaAw9rj5jPtNYocWBbIkFpJBCXX5HRtNKsaSLHBurmmCOiWfYO1xgT50QXg+LWwxsR3IgXaQ15K7Uk4vcG3Y0cdiOrCwCxooa81CwRoQbuyv2Fs2sW4SyN11iYXMUUcqoiTm+AHpegmwvbYkIAzlzzK6We4cLXPatx5TDewzYbqHPI0I97B3MY+bVhK+7JUgMI4YtBXKyq1GfmWvjjgE29TtIv2KpSyxdgFSTekWxRCsmps7mKL0Z97N49e5G5rOU0uo69xSLO9ll7IhKkAz7osK8+6alq/YczcuUk9qruOxTLH2ZEtt7FTn4iWXYidUtme8hGQ2TJY5WnkQQhEvEchL3rQjHMTApjAgEGcgW6UCdLz5C0URkqUIsukssmb7aCsj0blFdMxcerxazXqj38O7q9zP4WsPjnAomQywtUsoTpJT/n5TyP6SUT0mpanRLKS0p5eeAdbMzzHkKowWExgItW9fHEsr10idbWNxs8BrLlN29d4uyKcda6ysWz2FoNC6p/Xhhj7ogT1rRSmtMOeEzomrCGCwbNBk6iahGUah+4ppTxg6FK2GSWkRduHa98uguvMkrHI0TSaoy4cUGm31VTGEdKvBglaF8LAfSRY6KVpXMqvAwZtlh897UKMc9UoLjVHJZAJpFXpkXIwliY5TNz/h+p4kUS62PJaYimEI6LVqp5jwe0kVLqRXPNLPufer/jgdpj0cwy86YTcLufbmHp3YN8fiOgbr71YDUb5ugSHrgAKUKsbimMF2ZjsaqPzUm3FBix5F84ZebeS2j1RYVdYnlf9/1erV+m7/Hibs/J2PEI0pVLmoyqqawRccrf+JIP4vnvE8sUPtdtZ4nWinpUjGFeeH6o4hFlTapTJi+rPsnXbVy9MKkawpTrx2yjfFNYa6PRXdKE7aO8ODVCROTIZZIHF04FIq191lqeICIsHEIEaNUU5ooionU1TUf61DqLe8vRFk2VQL2wmOVb6tcrKoTT60ADMwxsQghrhZCHCWlzAkhjhdCfEEI8Q9CiOPrHH7eLIxx/kIIiHewSMvV7ckSLfUzKNo4sauFTeYS5VvZ/vtqJFe0jo+llFY3WaTx6BI/nt8zhB4SHL+0pWIKS8nqpNxrqV7f8YiumiiVMoSwcUQ1SkbX1WNnnJvKsYqUZQgjGsVIej1ZGjOFDeRKLNbSiNYuiHewXE+xZzBPX6bEEVpV9SzV1Plyps3ythh0Pw0bPgjfPgf+rQtuOY0lzVViScqcIuRwDGOMBEnPvxISjSVIxoSnWOLq944kadHMulGAqYJLLJ5/5Zi3Q6wdXrt/wuz7Z3eriWnrgbHt+qFSdbIPDe/EcvMswrHqIqREFDFZxeKawn7z0n629mTIytgIH4t6vHUY7n7JncA9J3p6b02TL0+xeEmSgIrealpa24IYqs77kKbUnUcsUhFLPKJVg0y8Wnv1TGFQNYdl9rvh0BGe2DFAIqJx8ZrF9KRLWE3q2JSMjRsVloho5IUvaKABFEb0YmkEXgkes1D7HoUhRY55YzFxSuRds6vtSKJYFWJpdonFTPnqhQ1sV/PMwuPUH0CvGxm2+wm18Iq1zwvF8llgrxDiaOAe4I0oAnlCCPEjIUTEO1BK+dzsDHMeI95RX7FYBQw7S8noZHl7nKdzbt5KfqAaGjyWYvFKZ0wBL+xJ8cYlTRhhDSMcIqKFGHJ8xGIqc0UiqlGQUZXfgq9rJBAJ65hSwxnHFCatAkUiRHWtUnSv0Z4syseSUsqtaQmLxTCv9WVxJCwW/ao8O7BQVlfvXW1xePwWVc8qvkCtgge2syRW/d4TTlapSN0gOkZr4mHXZNnZFG0gj8WpVSwAkSRNoljX9FklFteX0LoCjnwLvPYA7a5ZciJiebVnbGLRzSqxJHK7K4olEqsuQooiSmiMwoZjopTBiTRx4+9fRQ8JVVTUHG0KyxHjga1uXkQlOXFP5RrOYpCoEItBb6ZUNf0lF9bmVDhObTRaclFlZV0gSiyicpQcQiq8NrNPLbhGZtR74/BUYrbH518Z4JSV7azsUIquL6TuwawcPypMCFEpfdRoIcpRvVgagBZR15Q5olKCmVLEUkx2oQuHohsoUzTLaqHjS8AsHQAAIABJREFUEktbezs5Ga0t6+JGgf1iT5LrnxWAqDrw92yErlOVf3dgR8PjnAoaIRZdSlkAPgC8R0r5finlO4AjgE7g87M5wHmPeEd9H4vrRJSJhSxrjfGy5UvY6jiaB17p5dHXC5XWshWU0irccwqQUvJi9zAndqmLWwhBcyzMoO1rwGRFaDaUjyVHtBJR4lcsEU3DQh9XsVAuUiKMEQ6RTLZQliHsBnuy9GdKtMthNdk0LaZdDuL5JzvKvWpCjrbQWq4mf3W1xZQp8Yg3w5//N5x+FQAtVl+lhIbh5BSxhA2isn6CpOe4X9xsNOC8L/t8LC45R5MkRbFuyf0axSI0FZn0hj+G7AGWWLuA+mVd+jIl9gwWEAK2jkMsESuDLTQkgi4OMDCofrtooqpYTBEdVV9qXDgqWOKVIdjRn+PPzjiCjIwRskvVBFlf18Undw6qHJ5IXK18U90VYsnLqmJZ2Gxglp3q9zSSWMwsIKt+m2RnhRzybnRZPKLO5VVvpmmJqo/nR/OIJEk3674/W+LVnixnHNle8c/tlouRIZ39smNc5z2APUli8XqxRJONFaAE0KL1FYvjfk9mk1KFxbzaX3SrXQh3kdORiNIj2zDSPkd87xYI6XxrU4hfvDigyuX0blZm1J7NsOIMaH/DvFAs+1yz11uklBUjnZRyELgS+LNZGtuhgXi7W+F4hGnEvTj0lsV0tcUoYGAmXfvwgtXc9dJ+9uRCyOKIC7eYrutf2bQ3xcU3Psy51z/A2256hPd95wm27K/NG+nPmqSLZY5eWF3BtsR0+spVYkk7cdcUpqkmSh6xhCrCk7AmsNCR4ygWysWKYmmOhyfV7MvMDqBTVqvUpsU0W1UCaSodULbw5qVECz0V0uhqi6v8nza3nIi7chWZ/SxtUZ/PsDOuYokpxVKHOLyJblGzMWHr4oJl06RZqtaaV9AwkiCOSpD0N+5yHFXWp9kIVxP5Qhq8QVmHF/epfJZ6ZV08tXLu6k72DBbqRpyVyjZxJ0tRb6UUX8wK0Uv/kNv/I151qpuh6JgVc+vCJYX7d+Y5YVkL7zl5GRm8nu+Zmv8ZGcOyJY9uc38vL5fFXRxlXUIAZQoDX8hxcmG1SyT4glR8isWt8+Zl3mshQVQPqSATGG0GA0VM0RafKUzVCfP8K2cc2UFXu5rAdxYTbHnv/dzlnDEhsUgvyrJBYqn0YmmwZD6MXdtN5JVZrdy8Qg3Bjf4rVcooqe8jood4KHQ6KwYfr5pfe7dQbnsDrw1a9GZK2J3HKsXS/RQgVY+ajiOVybDBhOapoBFi+TfgWaBFCPEpUVsIxwGmtrw+XBDvoNlJj+rJYg4ru2esbQnL3BXTcMKdFBccxUvdKRVKadVTLLXEsmlvig98byPpgsXarlaWtho8sXOA326qrWy6s1+dy8tfAWiNR+ixqn4IL4Y/HtHJOFVikb5KsBE9hEkYZ5ySLsIqUJQRouEQzUaYjIyraKgGEPIqPieVKcwo9RNCTdJGfr+y3zcvQaRVLktIwJJoQa262o9Ur62sVPez2HXgh61MRbGEZWlcYlnSYmDaDrYzdhkaRSxmVa0ARJLEcPuO+37znFnGkVQVi+dkbumCBatp3vcIQN2Q42d3DxHWBO85Wb3Gi2QaOe4WkaMcaUK2reQI0cOQSyx+U5gljDEr5taF+5vtyYe5+sLVNLm/pdrnTv5uoqCMJGgydO5/xSUIL5ellEUiKBKpmMIWNvmSJMHt+thXjVByg1Se73OUec0LOUaZwuJue4R4RKs0MhuVw+KhxU2SdBzXFLaIjTsGiEc0TljWwqKmKHpI0D2UZzCyDIcQyTptif2Qk+wiaVd6sTSuWMJjJLTqbp0wWhSxWK6i8UxmnmIBuL/pnaqqx9PfVxt6X6Yvtqqyf7jpaKX0dzyoTIldpyrFAmr7LGFCYpFS/gRl8joNeA14UQjxbSHEV4CHgLtnbXSHAuLtJOw06ULthJHqVyuIls6uSkTTXuNoiDaTjy9jW2/GTcIaUWOrmKpRLB6pJKM6t3/kTG5+30l87y9PY3lbnO19tRf9zn71/A2dfsUS5oBbOt/RopiEVVRYRFNNlFyzieP3sWghTPRxM++FXcIkjKFrGGGNrIgTMifOvC/bDtGSW27dNYUJ6dBBirjuEMruV5Nx01LI7GdZa4zFzQbh1C71mvZaxUKmSiy66RFLnIg0KdaJwPKc9wtdp/94fpaC6ZAIWVX/CkAkieGoicBvDvMeV3ws/uilI89D2/0YUU3W9bE89/owxy9t4YRlao1WzxyWLlg0k8OOtBBe8AZWiB5M13kvfGHAlmagj1Exty5c0rC0BG9Z3UkyqsqZANUIxVIaS0RIxGKcc3QnD2ztU76TlmUVxWKFYmghjahbMbiqWNyxJBepjPj8YOWcAP+9Oc0t92+v6Z2iosIUQcUjOkVvPPUUC7i5LHtV2LG0oWkJT+wY5JQj2ghrIXQtxJJWg+6hQiWabzwfC4CYZDUJpzBMSeo0JRsPuqkWDa0llqg5QE5rRo+r68Fy++t4xBLyNf9bddRx3C9PRj7zQ/XdDu3iVad67e2NHAlIeH69ql4dbVKtNmBWI8MaCjeWUqallGUp5R3A24HXUUrlVuAjMz0oIcTFQoitQojtQojP1NkfFULc7u7fKIRY6dv3WXf7ViFEnWbzM4x4Bxo2spiuyVHID+7DkYKOhUtpiYVpiurc3fI++MhDvHwghyOVTVoga7NgfYrlQKpYIZXbrjqD5e3VC+qohUleG7Gy3dGfI6KFarostsTC7CsoM5cdURNQkxEmHtVJe70u8PW5x1UsUkeO42MJ2coU5iVV5kUCrYGeLIN5k043Rt9z3oNKkjwumUNIp2IKI9vD35x9BJ9927HVkEnPFBaOqRIdmf1uyLEkZKYqznugbj7HcN4iGdUrppDxiKVo2SRCZi2xRJNEXOd4PWJpNkJq9ewnlo6jEOUCR8RKo4jFsh1e3DvMySvaWNEeJ6qHeLVOZNhw3qJZKB+SvuBIOkW6mmTqU1Tl0Nil2OvCVSx2JIkQQpUzYaRiyVAIJUhGdc5740L6MiU270urz1hKQWYfxZAKNfYMGqMUS9INXvESGN337bMM+rOlWmJxTWGgFEsl5LhlOamCxTOvj8iX8pIkM0rBZ8IdbO3JcMaRVfXQ1RpXxOKaGScyhWkVYmkw+76YIk2C5lhk4mNdRAxFQv6ioY4jSVhDFCPthF0larvmcqvoVbuoXo9vOaaT71sXIvID8OC/AZLHs4s4slOR1jaU6iHfr/wrUFX9s+hnmUpJl91Syn+VUv71/9/em4fLdtZ1vp931VpVtWrY83jGnJyczCEhOSGBAIYAISCCrWLjGOxGnms7cenWa+u9jaK29G2vbWs7NCJeUHFovWpUEBEZFCQQAkmABDKcDOecvc/Zc83jeu8f7/uuWjXtXfuk9nA47+d5znNq71pV9e5VVe93/WYp5a9IKbfZP2JzhBAx4DdQDS+vBb5LCHFtx2H/FliTUl4B/Dfgv+jHXgu8GbgOuAf4Tf18O4cukswEG20zWerri6wwwsFJtZkfHPc5lRcwcTkPn1Yba6tza0QgTFYY8KmvL7FRrvM/v++WNlEBJSxPLRfbXDmnloocnUyFhY6ghGW1EkA8S13PYskklMUSTpEEZKz1hYi7DnXcTbsbO80qNREPN5JqLE28vrXbYKVQC/uEGYsF4Aq/wLUp/SUePaRcXTLgJbNNvuXGAxFhuaz1ZCMHILfA3dfO8T03TSpRSo62hKDRvcGul2uM+srSgs1rWcr1JmnR6QpL4zb7WyzTrKt0z6iwpNVn5Jhf6hKWRxdyVOoBNx8dI+YITsxmelosG+U6oxQR/lgorleJ52jitObnAM1Y/465PTHiYfqNuQ5lYYSlFWMpCTVx8c6rphEC5Q4zf+PS16k67ZlWfjzG/Giy5dYz/cBMnEXX5JyvxVnKV7tdYUZYEm4r9Xf0IL//L0/z7b/1L3zx2UjN1MhBFdPU2XhPVtTfcvORVurvoXGf02slCpXBhMXtNZ74/vf0bUXvVJWwmHUPQsJX5zmotbbQjXKdSZGjnpgkrmNnDT1qulmJ9OfTvPjyKR5wbuB88hh8/r0AfGxlkruvnSMVj/GVyoQaqQEqvgK628HsjmaG7cdBXy8CnpBSPqULMP8YeGPHMW8E3q9v/xnwSh37eSPwx1LKqpTyFPCEfr6dI9qIMrLRiMI5luQYc9rloj7Y6orjYd0ksq3BHiiXWLUVvP/ic+uMJF2une8O5l8xnaHWCNrmn59aLrbFVwBGfI98pYH0R8MhXyNJV31hZSv2QlvwfmtXmKMHDhlqboZEc2thMe1cAsdTnWm1xXLHbJ2XTJniu8ORNFIdlF07pY6NuAHIzkP+LDceHuMXX6vrKiIWSy9h2SjVGUt5JHRSwGa1LGF34w5XmKnIjgqLee8nGnrjHDvSekxKjT84lCh1xVgefEZtkGYTvHI22zPlWFksJdz0eOgOvMZ5lrLw21LTA9cn0WfGR086quqFEKFl23KF5Smikj6mMglecGhMCYuZ/7PyOGXhh/EVwzXzIzy6oJ8/7Aem42ta0M5V4xRrTUrxVtC7hBpNDJDyYpQCLZwjB3luVX1Gfv5vvtryEIwcACSc/RIAZ5sqK/JApLfcofEU53JVVorq3HSutRPP1+cg2ojyC/8vPPB7PY93azkK25jFAq3YmIwIy0qxyiQ5gtRUmJQR6CB7Qx/nJlrfAT8e47Zjk3xQvgZkQODEebI5w8mjygJ+dq0KM1erg43FAjueGbYfheUgEG0qdFr/rucxUsoGsAFMDvhYAIQQbxNCPCCEeGBpqc+wnEEw/cJEe4djr7xEzp3A1Y0dD4754eS/h89scGwq3dZhGFAusaARusK+9Nw6Nx4ew3G6P6zHdeaXuSJsBpJnVkocm24XljFdJNlMjFGOtVxhXRaL2+4Kq28hLGqSXevxdS870LCvZd3OpelPqQ0xPQMI3nSlyz2H9fkbPRiJoWhhWY1khBlG5iGni8NMb6vESCgEnqy2ZW5BKyXYbFybxljquldYR/DeaVSI0ewQFnUlPFLTCRVtFotyA817RVY6LJYHn11vG2x21WyWc7lqOIbYsF6qMUoRLz0enoeDYoWaSLYdF8SSJNi+sIhoJqKJ2RjRqRXIy1YblLuumuGh0+usedrKaNYoRWpYDFfPZXlyqUC10ex2hWnRMqnwK7r1UUPEVcW5vvJPJ2IUZMsVdnajjOsIHnx2nb9+WL/3pkjy7IMAnK6p9U9lWp9Pk3L8tcUCvtcaw92PjB+nIJOtKZJSqgLO9Wd7TsP06jnKzuCzWEC1dAHaXOFL+RqTYgORme4SnrqOxXiJdu/FK66a4T0bLyKIZ1lJHSPA4Zaj4xyeSPHsagmOvBimr+5wz16+9zGWb0SklO+RUp6UUp6cnp6+8CeK9AuLVmOnaitU4hEf73iKfLXBmfUyTy0Vuf3yifYhRtCWglmsNvjaYo4XHuldyXuFDtCbAP7Z9TK1ZsDlHRaLqb5fvuNn+exRFQ5TWWHtwkLUFRZTWWGbCYsbVMK5EABBfISULG057GtFt3MRZsJfzFVukPyCCgT7E6pwtJfFMtEhLNl55VppNlrCErFYkj1SjtfLymJJDiAsFdMrrCPGApCiffM3IpOumM0ucj2jB7bNOnnWuoRljZuPtorqrpxTm9PXz7dbLaXCBq4IiGcmwR+j6unGn47fdpx0/QsSllikel+EUyT1Oa3myAWtPmAvPTGJlPCFlURYzFqQSdKJdjfQNfMjNAKpLn4SI+p9Ma6wag4pWp/BczUfHI96LIkjCJMA/LjLqkyDl4b0FAsbFV5x9QzXzo/wXz78mHr/zLk+8wXwx1ksqer5qNAZYXlsMbdpOxdDNqlS6Bsmhb64rDI4g3ortTdCopGn6m6zW4b+XMlI66TVfJEJUcAbmUHEjbCo/SGottooRbnzqmlKJPnkdT/PB9Jv4fh0mvF0XFksqyXkq34O3vqx9teeOK7ei23OnBmU/SgsZ4Do0IVD+nc9j9ETLUeBlQEfO1zMsK/oTBYpGQ3WaKZbfmOTcvwRnSJ827HJlivMmNvmTU6M8sgZNazrhYd7V/KOppRbwlgsT4Wpxu0fbiMs5yZu5VTiahyhvnSpeIcrrCPGUpMuItCbYP5c6L81uEGNZsR9JhNm2Nfm7rDVooqxxKKjY7NzKvAaTdNNTag5M7mzashTfqHbYsmqOEzbFyQSY+k1RXK9VGfUj4dXxJu6wupNErLa4QpTwj3p1bpiLDFHkCicVWuIWgD+BCCYcvKsl+thXOx8XnVuvvnIuPrbf++buSajrko7W7vUCipg7ehO0pWsmvdej3UIi+fj0dx0rHQbVVO931pv0vfVhUUkxrIRtPprmXjfQqEebuoFmSQd73SFKZF8dCHfsk5NkaSu9gdljS8Xa5CZpSZ8UnE3dCml4zE+IF8P994HQrC4UeHgmM//9fprObNe5r3/9FTLYimvQWaO8/lKmPVnMLUsp9fKmzagNGQTHeOJ1yJFiNHbGr+Zp+Zts79fGAtsucIKa+r8JMdmW25fbbE0672F5dhUmiMTKT6weh0fOH8FJ48qL8qRiRSVesBSOWgfeQCtzLAdSjnej8LyeeCEEOKYbhfzZuC+jmPuA+7Vt78D+EepHK73AW/WWWPHgBPA53Z0tfEM0om3Vd83iqt4NBCR8ajmiunDX1ZXtLdfPtkdvI9YLGZm/Y19hAXgipk0T2qL5ZT+vzPGYjocb5Tr5CsNMgn1pU0n2i0W0WWxuAizOX3q/4a//fcttxPKzdRwIl9evZFuNZNlpVhl1tlARIK1KlaiLRbTg0oI7eo62xol0GmxhH2iFvpYLO1TJKWUbJRrTCWbnPjkj3JILG0evK8ZYWl3hQHMJhtdwjKSdBG9hlHFXPDHGZcbSNmq/jfxlRceGYfHPwrP/DOz5z9NNuF2xVlMy3x83VVBn4t6rKM5p96sTMC3jUf+DD7zP9p/V8ur3lx+673MJj2KIh2KtazmWW8mw4D3VFrVhSxulMPakqhFY7hsMk3CdXjMFPJGq+8rOZpea7MzAfyqkwxFH1QM4XQ9C4dOkqvUKVQbHBhL8uLjk9xz3Ry/+Ykn1VpNXEh3NZ6OuMGAsJZF/X1bC4uaIhlxhZnPIHS3nJeStCzS2K6wxDzquG2dEqrr6sLTH58Lg+5Cz9cJtLCYoL9BCMErrprmEzrZ55bLlJfjiBbTaBw2JKxl2Rl32L4TFh0z+RHgI8CjwJ9KKb8ihHiXEOIN+rDfBSaFEE8A7wB+Sj/2K8CfAl8F/g74YSnl5n07ni9CEKQm2mayrJxTzfYSY62+RmaG+wPPrHFo3Gd2JEFV6CsW4wqLxAm+9Nwal02mwuaFvbhiJsMT5wtIKTm1XCSbcJnKtB8fNqIs18lV6mHzvU6LRcS6YyxOUFOZYV/+c3VHuZXm6ckaQaz15Y3p6XzVjpkszUDytg88wH0PKZfWSr7CBBttWUA9LRYIa1nCK8RerjBQcZhQWMZaFktHI8pSrUm9KbksOM3Yqb/hVvFYX1eYlJJCtUFcVrqC9wCziXqXsPSsYTGkpxkJ1BpNAP/+U6skXIfrD46EnX/F4sMqM6zDYgnMMCd9npMzqt9cOLBNI/RVbrWjmhsp4R9+Du7/7fbnreQpdExUzOiZ71GLJXqM4whmR5IsrFfCvzXXTJDqcIW5MYcrZ7M8uthDWKo5am6HsMxcw7I725ZZlY67lGoNpJQs6gmjc7rTwhtuOkCp1uSZlVLrIsMIS7ZdWEwtCzCQKyyjLZbwHBhhcbxui6VWxKWpRoBvk6pI4ERcYfW8Oj+xzAw4DhUSONqikXpURTyZ7nqeO6+aCb3QJ48qYTGW5bM9hUWnHO9QZti+ExYAKeWHpJRXSimPSyl/Uf/uP0kp79O3K1LKN0kpr5BSvkhK+VTksb+oH3eVlPLDu7Fe0dEvbO2c8sFmJg+Ex0yk1YwJKeEFh0YRQhCEpm67xSITWb747Do3bWKtgIqz5CsNlvJVnloucmy6OytlLCIshUojvFpLx932GEskZdXTMRYnqMPjf9+aUGeK26QkIattwuLqflWljtb5q8Uaf//Vc/z4H3+R//XAc9Tyy8pllom6wuZVVXY1174pm8K3zhqW6OOgw2IZ6YixtFxdRggmHLXp+n06IAPkqw1KtaZK3Y1aLNqlMBnvYbF0Vt1HSU+Rbqhzs6Lbutyvi/gSbqw1q2ThIa6aU5lhsrNwFsI5PfFpdcU5Otr+GTEB4UqpQ1jOPAgbz6pYQYRGeYOCTLZdxWeSLjmZUu9Ho4po1ijI9uFYaiR0S1jWg0TPTKtr5rM8uqD/lmhbl0qHsBSq8Pr/xq9N/VyYWAHKYgkkVBtB2LL/gC6INSMTzq6XtxQWULUssHVxpDkHBVItN/XqKQqJGdYS890WS8d7sx3qIk4s0jRUmqw5nfBREUlixqLRAtRpsYDygMRdh8l0PPRahD3SVnr0jjMdpy8Vi+VixElPMum0Ohznl1VYZ3y2tcEIIcI4yw0H9WbgdbSN0FdH52sJzuerWwvLjHr8E+cLPVONQaUbQ8sVZjaHVKcrzO3uFSaCOjz0x2GANhQYHdQ3s7cBPN0uvJxrL17b0B0JJtNxfvLPH2ZlUSftpSMJExGXIWMRN5LJ+lp9Sn1pUx19mNLTqo9X/qyaUOilVU8vbWF0djg2VffjQm26vYL7BjVwS+I1Oy2W3jGWXKXOTEKPie0lLKlJkjV1/tZKNTZKdR5dzHHbsUmVZXROtzZfeJgrZ9KsleosR/qKOWbz0q4wY73NTLa3EDFV2Z39p/jqX6j/G+W2HlFBOUeBdtHIJlw2pBqpYDZWZbG0rNq50SSLuZaw5JsJMvFewjLCarGmLJL0jOruHTShukHFUecym3RZytfATZBvOh0Wi7pdqjVDi2VeW//GC7CwUQ5jPTV/hny10VtY9Pdvs5b5hpGkml7p1FsWy6nGNI9Vp7oslkZRfeaFP3hnY0NNJNt6uzm6T5hJ+Kg5SVwjPFpghNctLH48xneePMS/euHB8OIy6cWYG0n2tlhAxVl2KDPMCsswSE0yKfJhymlV9wmbmT/adpj5YL/gkLqy8eIJmsQirjBlsTy0rK5U+2WEGa7QKcdfOZvjzHq5p7AkPdVmI1euk6/Ww6u1dIcrLBaxWIQQNIRHsr4BX/8IXKvLiIwrTPt6zVwIgHhWbXDVQruwmM38l77tBdx55TQjgRanTovFEI1PjByEZlVl+xjTPYrjqBbp+UXdCkdfMRqLpcMiWdciN4LaLHsF9w2LG1XiNBAEHcKixHzc7Q7eH3HXuv8GQ3oar6rOzWqxzuefXkVKuO3yCTUdsVGGYy+HepGbfLW5RN1hsVokOQEiHQjaN5meHXOlhK/8VesCIWK1BJWctkZam20m4ZILfBUv01Z0QfptLiRlsZSRekMv9kg3Brh6TlmyX13IKYtFBur1q3lKWlgun84oiwUlIKmIQJnbxWqDsxsVhIAZLRpTmQReTHB2oxJaLBsx9Tmc6Sks27BYEh556RMzRb9rp3iyOc3X61PI1VNt2Y+mZX4stX1haThJYpFOCfHqitoTtMuz7vgRYanQwGk1RO3gF771Bv7P17fXkh+ZTPWOsYD6TlmLZR+TmmRc5FncKPPpJ5ZZP3+aCvFwAJbBXGFdf0BtDqmkS8XxO9KNBQ8s1Im7Dtf0KIyMMjuiAqYfe+wcUnYH7g2jvsd6ybjC1Icy6TmURNRiaf+wNoVHIiip9Mrb/536pXGFmcLDiBj5uvlevdA+AXG9VOe1zv0ccPP89vfdwr++RltGmY6ssHCx0RiLFpzFh7vdYAYT4I8KS5+sMJMenAnUhp0U1b7B+8VchWQ4i6W98h5gzK12FUgedpa7/wZDegpRXsUhYLVY5f5TK8RdR1mlCw+pY25W+ShXBOrL/piOTUgpiTdySERrpEJ2Tp2faCEmfTrmntVusKteq34uRdxh1R4xFt3WRVbybS3zo1bN3KhPpR6Q93XwXqa70o2hlRn22GK+FVfTWXxF3QPs2GSK5bw61+Vasy14b+I25XqThfUyM9lEWINiYj1RV9iKoy7GNrdYBnWF+XiNkrqQyi/wZH2KZ4JZRK2gLC9NaxbL4J2NDfVYEi9S0OrX1ih642HRaz3mE9e96USjQpXBW8YAYcqxIQhkayLl5HH1d5QHm6O0HaywDIPUJFlZ4JNfO8f3vPd+6hsLFLzJrmFd33PbUX72W64NM7VSnkuZZHu6cSLLF5/b4PoDI8Tdzd8eIQTHZzJ8/ml1pXz5VO88+lHf63KFCSEQXkuIYl77FzEc/DV7Axy+VVkBxhWmhUVGAseZMeXaMm4BQym3wm/F/zuXfe5nSbgx3nBcP28m6grTAuJ4rdYf0KpPkEF34D587JwK8Eebd/apYzFDvlJNtWGnRL2vK+xcrqKq7qGnK2zEqelkgEBnm9WZZzNhmUYgOZQos1qsc/+pVW46PKbqaRYfVmu++vXgJsmufoWpTCK0WIq1JllZpOamlZUG6rP1w59rib7GTfRobPiVvwTHI3ihTqQstjZFUSuQ7xCNTEKN5qWaC920edrnxJs4xxn3KGdf/Vt8JDjZ02IZS8WZH02qEQ/mvS2cg2qOPCnS8Rizo0mW9FCwcr3Z5gozt4vVBou5Shi4D9cx5qskguOvgKu+mefiyrJ9vsKS8mIU8XFkA5bUWORn5QzPSP03ROIs4SyW7PaFpRlr9Xar1JuMBOtUEy33ZiPmE9f3O40KNbr/rs04MpFiMVcJP+fv/rvHeNWvfFLdefP3w088eUGxoa2wwjIMUpM4SN5190H+4N/cyhvGnmbq2E1dh117YIS33NHaIFOJGCXhtwXvZSLLI2c2uOnwYCNOr5jOhHXAeFhKAAAgAElEQVQRl011+14BxlItYYm6M7xEkobQmT5u+wc2HPx145vV//5ExBVmLJaWK2wimyYvfWSpPXhfzalgbfqJv1YB6sI59bjoaIDUlHLTjB5sbZzQao0PvV1hoAKQJnjfZbG0C4exMJINJSwZp76JK6zCTFLf18NiyTrV8DnLdZVtNt1cUn9HZq7z6cJ6p2N+iWdXS3z5zAa3H9Mb0cJDaoysl1STMRce4pr5rLrKR6Unj4gida9jA0iOdA2+8nRgt2EaG0oJX/1LuPxO/usD+lxELJZYLd8VmFeNKH01RVK7Z4uyfU686Si9mKuyePi1VCMt8zu5Zn6ExxYiFsvaMxA0yAXKBTedSVBrBuQqDe0KiwqLes5yrcnZ9XIoaIYDo0nObpRVD7nv+iAL5fa2/VGOTaWJaStnKxxHUI/pC6/FRwB4Vs7yjNSWdiTOUtep4BcqLKa327lchSmRo5GcjNzvq8xEVOPXmti+xQKqfmcpX+X9n3maM+tlNazNH1exnAucVrsZVliGgd40vveGDC9NPkUsfwau+1dbPiyMc0TSjauxDJV6wE1HBvPXmjjLdDbRNyg56nssFarUmoEaRBW+fixsCeJ0WCzFWJYGLtzwJvULfxyMaIRBxGjtg8sGaUS5XVga+Yjb5RO/pHpFpWfaP8yOoyyPzthEZlbNkIDNXWG1vHKHGWFxYkjHUzGWSGPQ9VKdeMwhVlWmf8qpb+oKO2QMwKjF4sTAS5ER5fA5TWxtvLnUe8ohhMkKhxMl/vmJJQIJt10+qTb+xYdh/gXquPmbVGbYTJqvn8vTDGTYgHKQdFZjsYQzPs4+COvPsnrZ6/jDL+sLGBNjkZJYo6jdXNEYi0dB+qqpZ0HVVXS6y+a15XB2ozWYrF/sImztYjZMHTBeD5SgGetiKV9VrjAvGmPRFkutycJGJRS0cB1jPosblfDiailfxRH0TNOfGUnykbe/nG++Yb7rvl6EdTahsMyw7OrHRiyWpv5epLODz7s3BLGkqpUCPvboeSbZID3RujAJvBTJUFiq1J3tWSyHI7Us7/3np8JGuSYRYqewwjIMTLZSaUXVfLjJlj97E3wzxTESYzEBzatmB+s7dFz3Buts5RJlxPfCPmXRK9NUXLnimlLgdcRYPpR4Hf/56O+CqZBPTbSGgmmLJTpwyHEEBZElVm0vkGwa19iVr4WvfQhOfaq9hsVwyw+0rCNDLOIa6+sK02mmxfPtJr2XVK6wWtRiqTGa8hDap5x26lQ3cYXNp3WA1mt3v6hhXxX9nK16lnQz3525ZtBZPge9ApV6gBcTquJ+/Vllbc0ZYbkRqjluGc1RbQQ8vVJko6SGfA0ysjrht7cBUW4wl985fw056atxCEZYGlViskFBpnrGWNQfqDIcC6TaKuunswlijqqEL1bVOezX2Tds7bKOsv5WngBgLVBpzqaY8Xy+QqnW6GmxLOYqlGrNcFqo4cBokkYgVet9lLBMZhJtHb6jXDGTCfv3bUUQb1ksVSdF0Rvj6sPTLDvtmWGytEZe+oykt7aEOpGuT1JWaQaS+x46y7STZyRSphB4KXyq1BoBsaBK4wItlodPb/AH//JM6A4MxxnsEFZYhoG2WCieV1/kE3f3HC/cSToeIy8T6ooboJKjrIXFFDZuhbFYLp/uLyyjvhdemUc3EFV9n6SOG85VMTTdFM/FVKyg3gzIi0zoCjPN8Jx4+5e8GBvBq7cHAqUJ+L/ip5U7LX+2t7B800/AC3tMuR45oIS6l3sJ2t1lUWFx/e4YS6mu6nq0QKZErb/FslFhzu/hCgOIp/GD1hTJ0MXWLPT3V+sOx7OushpecGhMBal1YSTzN7b9f51QG9djC3lVI0MJMUDWUdxXn4OgWlKtQL70QerH7uL9X9ogHouxwgiNsMOw+tyVIiOFIVIcCGGvNhnPtjVDjTmCmWyChY3KlhZL2NplsaAsNy0sK42kcoVpi+XMWplA0h6817fN7KH5sQ5XmE6IMTUu5/PVnhlhF4I01fyLj7DkznFoPM3l0xmeDmZaFouUzJz/DF+VR8PU/m29hueTFDW+fi7P155bVBcs+iIEAC9FCmXJuUG1rT/fIExlVP3cez71JMVak5953TWAFZaLAyMsX71Picv13z7Qw/y4Sy5ItlssQgeH/a0DjKCuSK6ZH+Elx6f6HhMVqajLIxV3Kco4NVy8jkSBhOtQ02bz+z/zNH/7RJVAi0TdzN722r/kVW80jF8YYhUtLGNH4KVvV7d7CUs/pq5UcQenz0c121tYhJfEF/WuOpbRiLB0piMbGs2A5UI1EmPpsFgSGZUxR7vFkmjkNhEW1S9s2lGb+W1hfOVhFZeZvU79PHMNOB4HSl8j5ggeW8yxrscSD5LOmjQWS70MD74fSsv8dfY7KdWafO/tR1mVWRq59tb1dS/TVljbNuwrd4YAEWabRZkbTSqLpaaEpV+MxbR2+dqiTjnWVezL9USbK8ykxXZW3gNh66L5TleYccmtq42yX3HkBWEuDmt5npMzHBzzuXwqzZONGQLTY+vsFxkrneIvmy/tWcezJZ66APrTB57jgNBJFdEElnganyqleuOChEUIwZGJFMVak1ddM8s3XaVcsotWWC4CfL1JfPWvVJHeibsHelg6HqMQJFpui0qOAilcR7RVH2+GG3P48I+/TA3D6sNYm7C0+6/zQUJbLO0fhXhEWD7+tfOsyoyKn0hJQ7eWiA4cAqh5o6Sb7cLiVdfUMKrkKNz6g2o86qFbB/rbAHjdf4Xv/l/97+8jLLg+Kae78n7Md0Nh8fvUsSwVqgQSppJadDotlsQo8UYhfE4jLG491ypg7MSJQWqCcT098zYz3XDxYSWeRrzcBMxei3vuYY5NpXk0YrHEM1sHh/1kkrqM4VQ34NO/RnDkDt79lXFedmKKO66YZEWOEBhXmJke6bVnE4ZZYQC5s1SdFJke8TtTy1LQFktnE0qDG3N0QaWeFKm7LJ2vqbjgqO/hxQTP9BAWY708tVTUr9mZFaaEZmFDfSaXhmixxCIjnx+vT3No3Ofy6TTPyBmc4nl1Qfjwn1AXcT7p3dFzvMWWaFfXXz54mn87+WX1u2MvC+924ik80aRULuPJaltR8qCYOMuP3HUFqbianno+t40O2BeAFZZhEE+pzSeow9Wvax9GtQl+PKYaUVZbWWF5fEZ8b1sDg7bCpDdDu7siFXcpBHHquMQ7hMWLOdSbAZV6k88/vca6TKtK/FqBhplk1/F3BskxsrIAQWuzjtc3KMVGVLA+noIf+nRvl1c/kiPhBMaeJDKtDLOOGEvK6c4Km0pKVXSJSkfu5Qozgc0JzwhLh8Xij+HWNsLnNK18YtVcWNjWk/Q0B7witxwd51bdKJCFSODeMH8jLDzE1bMZvnYuR65QIiWquKmtg8MJ16FMnCvP/S3kz/JP8/dyPl/lB192OePpOKtkcUrtrrDQ5aNJxWMURMtiKQm/Z4ru/KgfusIcoWqj+jGVSahalUjHhXPVuGrcKQTTmYTq+YWy5A1x18GLCc6sl3FEd+HjqO+Risc4u14h0LGWYVks0VECX69PcXDc59hUhmdNZtjKE/DIn/FZ91YOzw+WENCJE0/hioBiuczr5D+p2SmR2iSh4zzVUp540N5GaVC+8+QhfvgVx8NOHrMjSRu8v2gw7rAB3WCgXAdFkoh6URVhNWtsyBQjA+TZb4eoK6wtKyyhhK0u+1gszYDPnVql1ghYQ28+5bXQYvESnRvuODECZLVltfiNDSru8PPk2zBWSzSF2fWVK6wezQqrMRdv9U1K9GnpYvzPY56er9NpsfhjiPI66XiM9ZKyWFwa6n3crCYgNcWEzPHnP/QSFZQuLKmY01wPYSmv8qKJEs+tlllfVSnbg7QMcRxBhQSp+hr1uZv5qS9OcvVclpedmGIiFWdVjuAa92TH9EhD2xTJWoEi/S0W1WqlSjrhbnoxNJWJd822VzEW3TE5mwgL+VId1rqx3meyya7AuxCC+VFVJLlWqtEIZFdn4wvF9Vvv5XNyhkPjKQ6P+5xx9N/w+d+F0jLvL97OK6/Zhns3golT3uI8zljxqVYWpiaWVNZktVQgTo3A3b7Fcvd1c/zEa64Of54bSXIub4Xl4iA1oTaV43cN/pB4rDWTJa/awKw3ExcUBNyM0b6uMJcPNl/Jrze/tSt4H48pV9g/Pa6ubjek9rGXVmkaV1iHxeLoK+pSTvmKg0CSCXLU4ttvdbEtTOV+1FrwksrVpWMstUZAsdZkxtVpuPEMcVntKSzmam7U1ZX1XRbLOJTXwsLTjXKd+WStew2dpKfaq94XdcV9l8XyQgBujKkA8ePPnt76uSNUdUeFX619C6ulOr/8phsRQjCeirMiR/CaJVWLpOunnGR3BqKIWDEF6fecYWJSf59YKmzZJmUqk9DC0rJYomnO05kEq3oImt+RXWZiN52Be8OBMZ+FjXLYFqZzFsuFkkylaUr1vXhGx1jcmEMwpjMUv/SHVLwxPhncyF1XX5iwmO/Qj4x9RvW9u/Zb2+8POykUiMsawQW4wjqZGUlwzlosFwkn/w286mfb2pxsRSrutsYT61knq43ebofnQ1RYokVu6XiMzwTX86fNV3QF7z1tsfzT48ucPDrOmjQWyypBaLG0C4ubUVZbXg8rylcajJOnkdx+fv+2MJ1tO7PCRCud2MRBJmM6npWdJyGrPWMsi7kqXkzgi1r4XG0kx6BRZjIpQ1fYgYQRlk0slvRUe3fhs19U/5uMMMPsdeC4HKupiu9GwbTMH8zyy4sMj8kj/ObZE/zSt93A9QfV47JJl3WhrbrSchi8d/zu542KTV4mewqHCaQ/eb7QN9XYMJVJsFaq00ipDTjw0gQ44Wc96r7qFBbzc2fgPrqOsxuVMG4wLFdYRk+RlAjOyGkO61Td6ek5ciIDQYPPJF/O3ESW49PbnB6pSaTU426v/DNc8aout6+rLZZ6KaemmV6AxdLJ3EiS8/kqQbD5tNfngxWWYXHLW5S4bIN0D4tluZ5oc1cNg1Ff5b4nPafN5ZWKbBadMZZEzGEpV+WxxTx3XTMTjsKlvBYOHIon2zfcRFZlppXW1ea5Xq4xLgoEye1XJG8L4wrrUcdS7hAW09mYkQN4stqWNWY4n6swk02qAUxusjsjzVdCeSBRCdON5+KV7jV0kppSKdtN7WI786AK3Hc+RlfgZ1ceIZtwVQ0L9E8M6ODd/jv4gepPcO9LLufbbm61l3EcQTWuRV43ggRwU91rTifjlHWcZSNI9rzYMe1VCtXG1haL3uxzMfX6Td3Z2zwuKgadImWSAjoD94YDYz5L+SpndMrxsFxhJjtuzZ1BxOJM6ec9Pp3mmUAJ5P9cv5W7rpq54JjowWn13YgFtS43GBDOvS8V8ySotbVRulDmdO3PSseY7GFihWUPCYP3ENYLnK/Hd0BY1PN1VuanI1/gXjGWvM72efmJaTCB49IqQb1CVXokvPbNJDWmhKWc08JSrDFOAecCmvNtiytfA9e8ob040fV1DEVZJOe1T3lMdzZm5ABeUKWsU2WjLOYqzI4kVNyr0w0G4QY/F6+EA9RmvUrbfT0x9QnlVVVxf/oBOHhL72MP3Iw4+yWunk0zgnbfDegKY+pKjh2/kp/55mu67grbhZSUsDSkg5/sTjbJJD2KWljWm8mew7FmsomwgUK/VGPDtB5AtyyVxVTXwhK6wqLC0vG52spiMUWTj5zZ6Hqu50M2qTocPyNnODjuh1lfx6bSPNw8xlrmBPfXL+eua2a3eKb+mOA8XrpnUbURlkphg4RotHW7uFBMu5udrGUZrs/Fsi1M8B4IheVcNcGRAWtYBiXuOvherMtPHrVYOmMsRmgm0nGunR/BTU9ABdUJtV6mgkeiIwsoM6r856bDca6QIyHqxDbL6hoGR25X/9r+gCRx2QrOf/7UGkLAYV+nWWbncQgIGnWCQLalii7mKlw9l4V6qTtwD6HFMuOW2SjXkUimkwNYLEZYiktqMmfxfH9hOXgzfOH3eMnEBitnils/d4T33XsSIUTP6nOZmoQSUFyhqWex9ArMZxOqu+8U3e1cDF7MYTqjZgeltqjhMFf755ojXAlUY2rDDIP3mf6usHQoLL2v1k3s5eHTKqFiK5EblEzC5Zca302pmeLgfOu1L5/O8N2Ne/n9II7viVZN0oVgLlyueX3Yhy5KIqUEuKkbhw5DWExs7FyuErpJh421WPYQ34u1ZqLklbAsN5JDt1hAWS2d7oxo9k0viwXgJccncRxBNp1WDTPLq9AoUyVO0m3fAEbGlbCYNi7l9XPqubP9izd3DNdvC85/5sllrjswgt/IQSweZvElqYX9kwznNiqqUWE/i0VbDtNuifWymssyEdPZZpsKiw5cF5fVjBlQAtKLA+r3t8afYYTtCYsbc/q2NHEy+r0oLavpkfSO6WUSeookUKC3KwxaVkSmR8v8KKGwVD3w0lR0g8eRXhZLh7AY0ersE2Yw1fePLeSHFrgHFY/8VHAjDzRPhK1QQFksDVweWw2444op1aH6Qhk9rD6PemRCJ8m0fs9LRlievytsdkSd650skrTCsoe0WywqxpKT/tCzwkB1OO50hUVnlHe26DdC87ITaiOaSMfZIAOlVWS9SkV2Wywj2QxFmQjbuNTy6suQHJlm1/GSeFK5wir1Jl98dl11JyivKYsj7IDcnhmWr9Qp1prMbSYs2mKZcEpU6gGrxRrjsQHcVamIxXLmC2pDmb2h97HTV4Prc6L+dUZFUVVcD+Fq1c9O0CAGxWWa5Rx52dtiySR1Vwj0kK9E78+ksSK2shJMjGW5UIXxo+RddZUfBu+jFovXKSzq5wP9ssL0GoaZagy0WfhmlhKo1Gmz7gvNBgsZPwo/fRYuu6Pn3SYrzKmoBI7ONkoXwnRGuTB3MjPMCsse0ivduEBq6FlhAG9/1Qne9vL21vPRSulOi8UUu730hBKF8VSc1SAD5TVEo6IGmXVYLDFHkBMZnIrqF1bXnY1TY3sgLK5PjCaNepUvPLNGrRnw4uOT3cIi2scXG7/z3GhyS1fYmFDxmnpTMkpRzZPZ7IrSWCylFRW4n3sBuH2aCsZcmL+R6fxXuH5CDh5f2YKxdJJVmUUWlwkq+U0tlvVAB+c3+UzOhRbL5p/ZdDxG0nNUkeR3/RGfPPKj6nEdWWFJz+mqYE8nXBzRPyjvx2OMpbotn+dLNK50aKL1vgohuFxngb3i6iF8tvtMhATCz19cj7XuTPG/ENyYw1QmwbkdrL63MZY9JOE6lEVLWJpemqDi7Igr7J7ruyuDoxP/OmMs33HLIY5OpsIrtclMnNUgTVBaQTSSVHvEWACKzkhYlW4sFy+zB64wc3XfqPCZJ5dxHcGtl03Av3RaLPXWRD3USGJgc1dYYgQQZI2LCsigiyM3yw7yx9UYgMI5lWq8VQeCgzfjPPB73HH8LlgdTsr2RDrOiswyXlhS0yP71Khkk622Lp1jiaMYV9hWMRYhRKuWZfxazgclfG81vKBJJ1x8L9YVXwF408lDW3Ylnh/1WS/VhyosUQv/4Fj7hn7H8UlGkm7fuM/Q0MKSrKmLtWFYLKBSjnfSFWaFZQ8RQkBc578HDRoJtQHvhCusF9HNoDPd+NB4KpwRDspiWSdDUDyPIyepECfhdm8CZXeERF23zjedjfu1kt9JTL5/vcxnnlzhxsNj6qq6vA5jh8PaFJ/2WhbzZVOusFKro0IUxwF/LBxxDJAOilunAzuO6iv39KehXuwfuDccvAU++5vw3P1qjOwQGNPV983CEqKWp8AsU71cYQmXnG5E2Tk9MoqxWHqNJe5ECYtKcY1OMzVMZxPhXJUo1x0Y5boDm8eXDo6pKZXDFJaUF0MIlcAXjbEA/OQ9V/d51JBxHCrESTc3QHTXjl0osyNJTq+Vtj7wArGusD3GiyfCKY41V4nMoJ2Nny+bucI6mUh7rEvlCnOaFWrEewaIq26rw3HY2djf4QLJXmhLw5M1HnpunZcc1wLRFWNp7xfW7grrY7EAJMfwIw03U838YMH19DSc/py6vZWwHFAV+JSWh+YKm0h7rJKF4gpOrdDXGslELJbO6ZFRzBX7Vq4wiFTf019Ytiq07IdZxzCFxXEEmbiLO+DUyZ2iKpKMSvVZc4cmLIkdTTe2wrLHpBMuVV0vUO3IlNlpom6Hzsr7TsZTcdbIEKttEGuWqfcZONRIjIZX8l51naJIb+5D3im0xZKgRiBR8RXoEhZf1NqGfS1uVBj1PZXps5mw+OMkGy2LJTGwsEyBDNSx/cYtGyYubwnKkOaSm7YusfIKbqOwaYylgImx+F2JH4YTMxnmRpJcObf1YLrpbDwUllyl3vWc33TlNHdccWFuU5NyPKzOxoZM0mV+LNk3y243qDpJJoT+TvWoOboQ5kaSrJXqPVsaDQPrCttjfC9GRSRJ0xrytRPB+16YzrH1puyKsXQykY6zLrMIGZCur1J3egctg+Q4WZlHBgEJ3dm4/wiyHSRikcRdR01rbFSVC8ofC4UnSXvwPiyOBNUWvV+lsz9O3IxqBrx6HpJbCAW0alkO3Nx/xoxBCGW1PPXxgavut2IirVxhXl1dAauMr94xlnNynADBCqNdjSEN4+k4n/3pVw702lO6H1gzkD0tlh975Ylt/jUtjk6oT1k0e2sYZJNuzzHHu0nd8ZlD9ewblrAYC2wpXw3b6g8Ta7HsMelELAzgF0UaR/Sfa7ETmDiLt8UmN56Os64bUaYbazRE7ytDkRonLpqUSzn85gYVb4cbUPYjIhwnj44rC0SPJFYWi/oyJahRrrViLOdyuoalUYPKelub9zb8sbYxzG5tYzCrwqQcb+UGM5g6l2FZLLp1vqHkpEj0sFYzCY+/C17E97u/TCk+fWGzRjqYyiQIJKwWa+Qr9aFa5q+5bpY/fOttnBhwpPegvOPVV/Kjd1244A2DupMkJlTsKd5j4NqFMKtjYzsVwN9XwiKEmBBCfFQI8bj+v6dzXghxrz7mcSHEvfp3KSHE3wohHhNCfEUI8e7dXf2F4cddikTTOr2hfIkHJR2P4Tpiy9cc872wdb6D7DvJLqYD9Rsr58g2N3a+s3E/TDaNqLXHV0ALi/pi+R1TJBc3KipwX1hUvxjpM2fDH0eU1/TVvkRUN5keGcUI1aDCcsAIy3DOYzbhsk5rnQ0307PPVSbpEuDwmeJ83/jKdjFFksuFKvnK1v3FtoMbcy7YjbYZ91w/vyPPux0asZYVlhiiKwx2rq3LvhIW4KeAj0kpTwAf0z+3IYSYAN4J3Aa8CHhnRIB+WUp5NfBC4A4hRHfznX1GtBGlKo7cXe9kKtE9i6UXbsyhEY9sSH2EJZ5Vm/jy+XOMUaC5052N++G1LJaXX6k386iwuN3BezOSeG40GRastk2ojJIcg8o6Y8kY4/EA0awN5q6aPK5ee9ApmodvU5mDU1cOdvwWCCGoRZqCdk6PNJhNP5DDc81OmX5hWlh2y+V7sdNwW2ISH5orTFff71CR5H57Z98I3Klvvx/4BPB/dBzzGuCjUspVACHER4F7pJR/BHwcQEpZE0I8CBxin5OKuxSkepPXA3/XAveGdDy2ZXwlJDWB6YfY7DPJLjmiru6Wlxe5TBQo+XuQagyhcPzn11/B7CG94bdZLC1hMRbL+bwaSTw/6kP+UXVsP2Hxx0EGzPoNarIKNQazWK77Nrj8zlasZSsy0/CTp4aaABH4E5henDK+ubB03n4+mIytxY0K5Xqzb0KApZ0gIizDqmMZ9T0SrsP5/M4USe43i2VWSqkvFVkEerUNPQg8F/n5tP5diBBiDPgWlNXTEyHE24QQDwghHlhaWnp+q34emLnzAGvNnekTtvnru13tXPohIvUoso+wpHQjyvzyWbKijLMXNSwQWiyz0Qu8NovFuMKqYa8wMzd9fjQZdkLoLyxKrA7Ey8wn9JdzEGFxnMFFxeDGNy+83C6p1uvLRO+YRMwRYepvr5YvF4Jp6/L0iiostRbLYESFZdPODttACLGjI4p3/Z0VQvwDMNfjrp+J/iCllEKIbU+iEUK4wB8BvyalfKrfcVLK9wDvATh58uTOTbzZglQixkaQAAdWm/2b/e0U6USsqziyH4nMOMGywEH2HZGanVC9k8SqOvWxzA53Nu6Hyeaqt0YRtwmL4yDdJH6jTl5X3i/oL9n8WBKeW4BYon9xp67N+a4bRqhWXPg0Q4uD7DTx7CTBefU+OsmRvsdlEi6lWrNvceR2ySbURczTy8rstcIyGFLHC+u4eM7zaHjZwU5W3+/6OyulfFW/+4QQ54QQ81LKBSHEPHC+x2FnaLnLQLm7PhH5+T3A41LKXx3CcneclOcqi8WBpdrwxxJvxXgqPnBwdiztkyfNKIW+I1JH9EyWdOFpAOLZPegTBm0tXULKayBiuiULCDdJJlZjSbvCFta1sIz6KsaSnetvKWhheckBB5rxi0pYRtM+G2QZJ0fM30RYki7n89WhCYAQgulMgqeWjcViXWGDIHR/sCpxhnnGZkeTPHJ6fYjP2GK/ucLuA0z/6HuBv+pxzEeAu4UQ4zpof7f+HUKIXwBGgbfvwlqHQjrRap2/tAPTI7fiP7zmKn7ju/u0bu9gIpJy3G9EaiyRokycqZqa054c3SNhCS2WSNuK8ppyYRmx8HzSTiMM3p/dKJOKxxhJusoV1s8NBi0RKa9BRacdDykleKeZSHss61HT3ibCYjb+YWZvTWXinFpWAZ4Ra7EMhp7TUutTlHyhzGYTLOYqSDl8h81+E5Z3A68WQjwOvEr/jBDipBDivQA6aP/zwOf1v3dJKVeFEIdQ7rRrgQeFEF8SQrx1L/6I7RCdInm+ltj1rLDZkeTAuf8T6ThrUgd7N5m9XRBZjqJiFOnxPRKWmKcaPtY7LJZoexnPJyXqYa+wxY0K86NJlX6bX+ifagyt522mr28AABAbSURBVKmst4RlSEWMO814Ks6qEZbUJsKiBWVY6cagUo7N+bYWy2A4unal3qd27EKZG03iCEGh2j1F9fmyry4ZpJQrQFcZr5TyAeCtkZ/fB7yv45jTwN71XbhA0nE1VxtgXaZ33WLZDuMRYZGbzAYpOlmmpZ7FshdDvkBZJa7f7QqLCovrk3Jac+/PblSUG0xK5Qo7cXf/5/cjFkugCywT/Tfp/cREOs6yHKEoE6T9/puVsVSGa7G0Xs/GWAYjFJY+Kf4Xyg/ccYy3vmyAbhEXwH6zWC45UvEYH2rexkMn380Zpnc9xrIdJnSHY1DxiX5UvdYGK3p1B94tvGR38L7DYvFFnYoO3i9ulFVGWDWnWr9s5grzfGW1ldeV1eKl+s9W2WeMp+N8LTjCU3J+U6vBWCrDvNiZyrbOkRWWwXB3yGLZyf5nVlj2mJS2WB4cvwfY31821dZFCctm+fRV3calQhyGMJjogtnKYvH8sFdYvRlwPl9lfsyHvKm6P7D58yfHWjGWiyRwD8oV9uvNb+WNtV/YNOMrs0OuMIN1hQ2Gl9Rz752L48IFrLDsOWY8sMkn38+usImIsGw2e7upN9mCs8euoS6LZb3DFZbEp0a51uRcroKUuoYld1bdn+2VFR/BH9fCsn7RBO5BWZ4ShwBn0wsZc99OuMISrjNw/dSljuur71y/ouT9yP69PL5EMEVoJp98t4P322FCt84HiMX7u8KkbuNScvd4s41aLM0GVDe6LJYENSr1IBR2VRypLZbNXGGgnquyoeI5F0ngHmA83bp42Uw0dtJi2c+W+X4jHgrL3s2E2S72kmGPMZ2MFy4CiyWbdDnNHA3pEPj9g/JOSm3e1b0WlqjFEmZudQqLCt6f1ef/wJgPeWOxbCUsUVfYxWOxZBJu2MZnkBjLsAokQc1k2ep1Le0kUsoV1q92bD9ihWWPMcO2QlfYPg7eO47g4eRJXlr97zQz/TddT1fb1xJ71IDS4CZbFku06j5yf1xWqdSaLKwrAQobUCZHt44P+ePKvVa+uFxhQgjGU2aD7y8atx2b5NXXzg51Xoe1WLaPFRbLtjEWy2KughDDvTrcCcbTCRaZVPNN+mA6HO9ZZ2OD57cslqLuB9dmsaTwghqVRsDCRoVMwlUWY34BslsE7uGiDd4DAwnLFTMZfuf7T276Xm+XUd/DiwkrLNvAuML81J6MzLsg7Lu7xyQ9ByGg1gjIJtxdncVyIYzraXq9hkMZUqM6xXgvZt1HiVosz3xa/T9/Y+t+L0lcVqg0mixslJW1AlpYtgjcg/r76kWoi4vKYoFWnCW9yxcyQggm0wmyif1rme83hK68P3Fwj4qNLwArLHuMEIKUF6NYa+5rN5hhQl/pJrz+wjI7q672Dx/c46kFUYvlyY/D3A2QmYncnyImG1TrdRZ01T2ggvfTV2/9/GHAXl50wjKRjpP0nIFm8Qybf3/3lUMfIfwNjW5COazOxruBdYXtA1L6qvFicA8YiyXp9nePuBOXwdhRxq+4bZdW1W8h2mKp5uG5z8Lxu7rvBxKyxjMrJQ6M+hA0lbAMarGEty8uV9jx6QyXTe6Na+VNJw/zkj2eynhR4cTgjb8BN33PXq9kYPb/TnYJYFKOLwqLRbtQNrNYSI7A2x/epRVtguerXmFP/zMEDTj+yu77AZ8qK+WkcoUVl0A2t84Ig3Yxucgslh975Ql+6M7je70My6C88Hv3egXbwgrLPiAVH37rjJ3CBH0Tm1gs+wY3CY0yPPmPqqblyO3t90emSAIcGBtgwFeUaHLCRSYsXmxv3GCWSwP7ydoHtCyW/a/zJsB9MYggng/NGjz+UbjspeB2VC5rV1hSKGEJ57DA5p2NDW0Wy8XlCrNYdhIrLPuAUFgugs36nuvm+OAP3saRyT3sATYoplHm2im4oqtpdpfF0j6SeIB0Y//itVgslp3ECss+oCUs+99icWMOLzl+kQReo1k0nYH7yP2hsIz5SliEA+kBUjujYmKFxWIJscKyDzBFkhdD8P6iwlgsI4dg6soe9+vgvaiRTbiqN1ZuATKzEBtA5J0YJEYBcdHMYrFYdoP9f4l8CWA6HF8MrrCLCmOxHH9F79n1EYtlfmybxZEGf0yNl3PsNZrFYrDCsg8Is8IuguD9RUUoLD3cYJH7k9RU4B6UsIwfG/w1/HFg+DPDLZaLGXuZtQ+4mIL3FxWXvQxe+g646rW979euMl9UI1X3W8y67yQ9BXs5JdNi2YfYS+R9gBEW20p8yPhj8Kp39r9ft8pIUGd6VLd/Ka9tzxX26ne1T6m0WCxWWPYDphGgdYXtMp6yUq6f9rjqyqnW5MiRbfQ4m71uBxZmsVzc2J1sH3DPdXOUa02ODHHuhWUAdFbYm184DUfG4Sndhmb04B4uymK5+LHCsg+YzCR468su3+tlXHrEXHC8Vgfk0GKxwmKxPB9s8N5yaRNtrZ87rf4fGaDq3mKx9MUKi+XSxvNVo0pQFos/cVHNvbBY9iNWWCyXNm5StdYH2Dhj4ysWyxDYV8IihJgQQnxUCPG4/r/nbFshxL36mMeFEPf2uP8+IcSXd37Flosez4d6Sd3OnbXxFYtlCOwrYQF+CviYlPIE8DH9cxtCiAngncBtwIuAd0YFSAjxbUBhd5Zruejx/FYdSu60FRaLZQjsN2F5I/B+ffv9wLf2OOY1wEellKtSyjXgo8A9AEKIDPAO4Bd2Ya2WbwRcHbyvlVRxpA3cWyzPm/0mLLNSSj0Qg0VgtscxB4HnIj+f1r8D+Hng/wFKW72QEOJtQogHhBAPLC0tPY8lWy5qTFaYSTUe3UZxpMVi6cmuC4sQ4h+EEF/u8e+N0eOklJJtdPcTQtwEHJdS/sUgx0sp3yOlPCmlPDk9PcDsDcs3JsYVZlONLZahsesFklLKV/W7TwhxTggxL6VcEELMA+d7HHYGuDPy8yHgE8CLgZNCiKdRf9eMEOITUso7sVj64SZV8N4WR1osQ2O/ucLuA0yW173AX/U45iPA3UKIcR20vxv4iJTyt6SUB6SUlwEvBb5uRcWyJZ6v0o03zqifrcVisTxv9puwvBt4tRDiceBV+meEECeFEO8FkFKuomIpn9f/3qV/Z7FsH1MgmTuj2t/b4kiL5Xmzr3qFSSlXgFf2+P0DwFsjP78PeN8mz/M0cP0OLNHyjYab1MH7M9YNZrEMif1msVgsu4uXUsH7DVvDYrEMCysslksbPZOF1VO2nYvFMiSssFgubfQUSRplG7i3WIaEFRbLpY2eew9sb3KkxWLpixUWy6VNNAvMWiwWy1CwwmK5tIkKi42xWCxDwQqL5dLGjQhL1losFsswsMJiubQxWWGpqdZti8XyvLDCYrm0Ma4wG1+xWIaGFRbLpY1xhdl2+RbL0LDCYrm0sRaLxTJ0rLBYLm1CYbEZYRbLsLDCYrm0yczCN/0UXP/te70Si+Ubhn3V3dhi2XWEgFf8x71ehcXyDYW1WCwWi8UyVKywWCwWi2WoWGGxWCwWy1CxwmKxWCyWoWKFxWKxWCxDxQqLxWKxWIaKFRaLxWKxDBUrLBaLxWIZKkJKuddr2HOEEEvAMxf48ClgeYjLGRZ2XdvDrmt72HVtj2/UdR2VUk53/tIKy/NECPGAlPLkXq+jE7uu7WHXtT3surbHpbYu6wqzWCwWy1CxwmKxWCyWoWKF5fnznr1eQB/suraHXdf2sOvaHpfUumyMxWKxWCxDxVosFovFYhkqVlgsFovFMlSssAyAEOJ9QojzQogv97lfCCF+TQjxhBDiYSHEzftkXXcKITaEEF/S//7TLq3rsBDi40KIrwohviKE+PEex+z6ORtwXbt+zoQQSSHE54QQD+l1/VyPYxJCiD/R5+t+IcRl+2RdbxFCLEXO11t3el2R144JIb4ohPibHvft+vkacF17cr6EEE8LIR7Rr/lAj/uH+32UUtp/W/wDXg7cDHy5z/2vAz4MCOB24P59sq47gb/Zg/M1D9ysb2eBrwPX7vU5G3Bdu37O9DnI6NsecD9we8cx/w74bX37zcCf7JN1vQX4H7v9GdOv/Q7gg73er704XwOua0/OF/A0MLXJ/UP9PlqLZQCklJ8CVjc55I3AB6Tis8CYEGJ+H6xrT5BSLkgpH9S388CjwMGOw3b9nA24rl1Hn4OC/tHT/zqzat4IvF/f/jPglUIIsQ/WtScIIQ4B3wy8t88hu36+BlzXfmWo30crLMPhIPBc5OfT7IMNS/Ni7cr4sBDiut1+ce2CeCHqajfKnp6zTdYFe3DOtPvkS8B54KNSyr7nS0rZADaAyX2wLoBv1+6TPxNCHN7pNWl+FfhJIOhz/56crwHWBXtzviTw90KILwgh3tbj/qF+H62wfGPzIKqXz43ArwN/uZsvLoTIAH8OvF1KmdvN196MLda1J+dMStmUUt4EHAJeJIS4fjdedysGWNdfA5dJKV8AfJSWlbBjCCFeD5yXUn5hp19rOwy4rl0/X5qXSilvBl4L/LAQ4uU7+WJWWIbDGSB65XFI/25PkVLmjCtDSvkhwBNCTO3GawshPNTm/YdSyv+vxyF7cs62WtdenjP9muvAx4F7Ou4Kz5cQwgVGgZW9XpeUckVKWdU/vhe4ZReWcwfwBiHE08AfA3cJIf6g45i9OF9brmuPzhdSyjP6//PAXwAv6jhkqN9HKyzD4T7g+3Vmxe3AhpRyYa8XJYSYM35lIcSLUO/3jm9G+jV/F3hUSvkrfQ7b9XM2yLr24pwJIaaFEGP6tg+8Gnis47D7gHv17e8A/lHqqOterqvDD/8GVNxqR5FS/kcp5SEp5WWowPw/Sim/t+OwXT9fg6xrL86XECIthMia28DdQGcm6VC/j+4Fr/YSQgjxR6hsoSkhxGngnahAJlLK3wY+hMqqeAIoAT+wT9b1HcAPCSEaQBl4805/uTR3AN8HPKL98wA/DRyJrG0vztkg69qLczYPvF8IEUMJ2Z9KKf9GCPEu4AEp5X0oQfx9IcQTqISNN+/wmgZd148JId4ANPS63rIL6+rJPjhfg6xrL87XLPAX+nrJBT4opfw7IcT/BjvzfbQtXSwWi8UyVKwrzGKxWCxDxQqLxWKxWIaKFRaLxWKxDBUrLBaLxWIZKlZYLBaLxTJUrLBYLBaLZahYYbFYLBbLULHCYrFYLJahYoXFYtlnCCGOCyFWzbAlIcQBPRzqzj1emsUyELby3mLZhwghfhD434GTqKaBj0gp/8PerspiGQwrLBbLPkUIcR9wDDVL49ZIV1yLZV9jXWEWy/7ld4DrgV+3omK5mLAWi8WyD9HDyB5CzUB5LXCDlHLfjaG2WHphhcVi2YcIIX4XyEgp/7UQ4j3AmJTyO/d6XRbLIFhXmMWyzxBCvBE1qfGH9K/eAdwshPievVuVxTI41mKxWCwWy1CxFovFYrFYhooVFovFYrEMFSssFovFYhkqVlgsFovFMlSssFgsFotlqFhhsVgsFstQscJisVgslqFihcVisVgsQ+X/B1QytSmzc7jnAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(x, y - res_psf.y_fit, label='Recovered Noise')\n", - "plt.plot(x, noise, label='Actual Noise')\n", - "plt.ylabel(r'$\\delta y$', fontsize=12)\n", - "plt.xlabel('x', fontsize=12)\n", - "plt.legend()\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.2" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/maxsmooth/best_basis.py b/maxsmooth/best_basis.py deleted file mode 100644 index ae8531b..0000000 --- a/maxsmooth/best_basis.py +++ /dev/null @@ -1,249 +0,0 @@ -""" -As demonstrated, this function allows you to test the built in basis and their -ability to -fit the data. It produces a plot that shows chi squared as a function of -:math:`{N}` for the 7 built in models and saves the figure to the base -directory. -""" - -import numpy as np -import matplotlib.pyplot as plt -import os -from maxsmooth.DCF import smooth - - -class basis_test(object): - - r""" - **Parameters:** - - x: **numpy.array** - | The x data points for the set being fitted. - - y: **numpy.array** - | The y data points for fitting. - - **Kwargs:** - - fit_type: **Default = 'qp-sign_flipping'** - | This kwarg allows the user to switch between sampling the - available discrete sign spaces (default) - or testing all sign combinations on the derivatives which can - be accessed by setting to 'qp'. - - base_dir: **Default = 'Fitted_Output/'** - | The location of the outputted - graph from function. This must be a string and end in '/'. If - the file does not exist then the function will create it. - - **N: Default = [3, .., 13] in steps of 1 else list or numpy array** - **of integers** - | The DCF orders to test each basis function with. In - some instances the basis function may fail for a given - :math:`{N}` and higher orders due to overflow/underflow - errors or ``CVXOPT`` errors. - - **pivot_point: Default = len(x)//2 otherwise an integer between** - **-len(x) and len(x)** - | Some of the built in - models rely on pivot points in the data sets which by defualt - is set as the middle index. This can be altered via - this kwarg which can occasionally lead to a better quality fit. - - **constraints: Default = 2 else an integer less than or equal** - **to N - 1** - | The minimum constrained derivative order which is set by default - to 2 for a Maximally Smooth Function. - - zero_crossings: **Default = None else list of integers** - | Allows you to - specify if the conditions should be relaxed on any - of the derivatives between constraints and the highest order - derivative. e.g. a 6th order fit with just a constrained 2nd - and 3rd order derivative would have zero_crossings = [4, 5]. - - cap: **Default = (len(available_signs)//N) + N else an integer** - | Determines the maximum number of signs explored either side of - the minimum :math:`{\chi^2}` value found after the decent - algorithm has terminated. - - chi_squared_limit: **Default = 2 else float or int** - | The prefactor on the maximum allowed increase in :math:`{\chi^2}` - during the directional exploration which is defaulted at 2. - If this value multiplied by the minimum :math:`{\chi^2}` - value found after the descent algorithm is exceeded then the - exploration in one direction is stopped and started in the - other. For more details on this and 'cap' see the ``maxsmooth`` - paper. - - cvxopt_maxiter: **Default = 10000 else integer** - | This shouldn't need - changing for most problems however if ``CVXOPT`` fails with a - 'maxiters reached' error message this can be increased. - Doing so arbitrarily will however increase the run time of - ``maxsmooth``. - - """ - - def __init__(self, x, y, **kwargs): - self.x = x - self.y = y - - for keys, values in kwargs.items(): - if keys not in set([ - 'fit_type', 'base_dir', 'N', 'pivot_point', - 'constraints', 'zero_crossings', 'chi_squared_limit', - 'cap', 'cvxopt_maxiter']): - raise KeyError( - "Unexpected keyword argument in basis_test().") - - self.fit_type = kwargs.pop('fit_type', 'qp-sign_flipping') - if self.fit_type not in set(['qp', 'qp-sign_flipping']): - raise KeyError( - "Invalid 'fit_type'. Valid entries include 'qp'\n" - + "'qp-sign_flipping'") - - self.base_dir = kwargs.pop('base_dir', 'Fitted_Output/') - if type(self.base_dir) is not str: - raise KeyError("'base_dir' must be a string ending in '/'.") - elif self.base_dir.endswith('/') is False: - raise KeyError("'base_dir' must end in '/'.") - - self.N = kwargs.pop('N', np.arange(3, 14, 1)) - for i in range(len(self.N)): - if self.N[i] % 1 != 0: - raise ValueError( - 'N must be an integer or whole number float.') - - self.pivot_point = kwargs.pop('pivot_point', len(self.x)//2) - if type(self.pivot_point) is not int: - raise TypeError('Pivot point is not an integer index.') - elif self.pivot_point >= len(self.x) or \ - self.pivot_point < -len(self.x): - raise ValueError( - 'Pivot point must be in the range -len(x) - len(x).') - - self.constraints = kwargs.pop('constraints', 2) - if type(self.constraints) is not int: - raise TypeError("'constraints' is not an integer") - if type(self.N) is list: - self.N = np.array(self.N) - if self.constraints >= self.N.min() and \ - self.constraints < self.N.max(): - self.N = np.arange(self.constraints + 1, self.N.max()+1, 1) - elif self.constraints >= self.N.max(): - raise ValueError( - "'constraints' exceeds the number of derivatives" + - " for highest value N provided to the function." + - " Lower constraints or increase the range of N being" + - " tested.") - - self.zero_crossings = kwargs.pop('zero_crossings', None) - if self.zero_crossings is not None: - for i in range(len(self.zero_crossings)): - if type(self.zero_crossings[i]) is not int: - raise TypeError( - "Entries in 'zero_crossings'" + - " are not integer.") - if self.zero_crossings[i] < self.constraints: - raise ValueError( - 'One or more specified derivatives for' + - ' zero crossings is less than the minimum' + - ' constrained' + - ' derivative.\n zero_crossings = ' + - str(self.zero_crossings) - + '\n' + ' Minimum Constrained Derivative = ' - + str(self.constraints)) - - self.chi_squared_limit = kwargs.pop('chi_squared_limit', None) - self.cap = kwargs.pop('cap', None) - if self.chi_squared_limit is not None: - if isinstance(self.chi_squared_limit, int) or \ - isinstance(self.chi_squared_limit, float): - pass - else: - raise TypeError( - "Limit on maximum allowed increase in chi squared" + - ", 'chi_squared_limit', is not an integer or float.") - if self.cap is not None: - if type(self.cap) is not int: - raise TypeError( - "The cap on directional exploration" + - ", 'cap', is not an integer.") - - self.cvxopt_maxiter = kwargs.pop('cvxopt_maxiter', 10000) - if type(self.cvxopt_maxiter) is not int: - raise ValueError("'cvxopt_maxiter' is not integer.") - - self.test() - - def test(self): - - if not os.path.exists(self.base_dir): - os.mkdir(self.base_dir) - - def fit(model_type): - - chi = [] - N_passed = [] - for i in range(len(self.N)): - try: - - result = smooth( - self.x, self.y, self.N[i], - model_type=model_type, - fit_type=self.fit_type, pivot_point=self.pivot_point, - constraints=self.constraints, - cvxopt_maxiter=self.cvxopt_maxiter, - zero_crossings=self.zero_crossings, - cap=self.cap, chi_squared_limit=self.chi_squared_limit) - - if model_type == 'loglog_polynomial': - chi.append(np.sum((self.y - result.y_fit)**2)) - else: - chi.append(result.optimum_chi) - N_passed.append(self.N[i]) - except Exception: - print( - 'Unable to fit with N = ' + str(self.N[i]) + ' and ' + - str(model_type) + '.') - - if chi != []: - chi = np.array(chi) - min_chi = chi.min() - for i in range(len(chi)): - if chi[i] == chi.min(): - best_N = self.N[i] - else: - chi = np.nan - min_chi = np.nan - N_passed = np.nan - best_N = np.nan - - return chi, min_chi, N_passed, best_N - - chi_poly, min_chi_poly, N_poly, best_N_poly = fit('polynomial') - chi_np, min_chi_np, N_np, best_N_np = fit('normalised_polynomial') - chi_log, min_chi_log, N_log, best_N_log = fit('log_polynomial') - chi_loglog, min_chi_loglog, N_loglog, best_N_loglog = \ - fit('loglog_polynomial') - chi_leg, min_chi_leg, N_leg, best_N_leg = fit('legendre') - chi_exp, min_chi_exp, N_exp, best_N_exp = fit('exponential') - chi_dif, min_chi_dif, N_dif, best_N_dif = fit('difference_polynomial') - - plt.figure() - plt.plot(N_np, chi_np, label='Normalised Polynomial', c='b') - plt.plot(N_poly, chi_poly, label='Polynomial', c='k') - plt.plot(N_dif, chi_dif, label='Difference Polynomial', c='r') - plt.plot(N_log, chi_log, label=r'Log Polynomial', c='g') - plt.plot(N_loglog, chi_loglog, label=r'Log Log Polynomial', c='orange') - plt.plot(N_leg, chi_leg, label='Legendre', c='purple') - plt.plot(N_exp, chi_exp, label='Exponential', c='magenta') - plt.legend() - plt.xlabel(r'N') - plt.xticks(self.N) - plt.ylabel(r'$\chi^2$') - plt.yscale('log') - plt.tight_layout() - plt.savefig(self.base_dir + 'Basis_functions.pdf') - plt.close() From d9e3c737d865586c28b06b371ca09c883b8691bf Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 14:26:02 +0000 Subject: [PATCH 43/52] remiving the new test script --- qptesting.py | 59 ---------------------------------------------------- 1 file changed, 59 deletions(-) delete mode 100644 qptesting.py diff --git a/qptesting.py b/qptesting.py deleted file mode 100644 index 0d3c1e0..0000000 --- a/qptesting.py +++ /dev/null @@ -1,59 +0,0 @@ -"""Example use case for the qp solver.""" - -import time - -import jax -import matplotlib.pyplot as plt -from jax import numpy as jnp - -from maxsmooth.models import difference_polynomial, difference_polynomial_basis -from maxsmooth.qp import qp, qpsignsearch - -jax.config.update("jax_enable_x64", True) - -function = difference_polynomial -basis_function = difference_polynomial_basis - -key = jax.random.PRNGKey(0) -x = jnp.linspace(50, 150, 100) -y = 5e6 * x ** (-2.5) + 0.01 * jax.random.normal(key, x.shape) -N = 11 -pivot_point = len(x) // 2 - -qpsignsearch = jax.jit( - qpsignsearch, - static_argnames=("N", "pivot_point", "function", "basis_function"), -) -start = time.time() -results = qpsignsearch(x, y, N, pivot_point, function, basis_function) -print(results[1], results[0]) -end = time.time() -print(f"Fast QP Search: QP solved in {end - start:.5f} seconds") - -qp_jitted = jax.jit( - qp, static_argnames=("N", "pivot_point", "function", "basis_function") -) -start = time.time() -status, params, error = qp_jitted( - x, y, N, pivot_point, function, basis_function -) -print(params, status) -end = time.time() -print(f"First Call: QP solved in {end - start:.5f} seconds") - -vmapped_fit = jax.vmap(function, in_axes=(0, None, None, None)) -fit = vmapped_fit(x, x[pivot_point], y[pivot_point], results[1]) - -plt.plot(x, y, "o", label="data") -plt.plot( - x, - fit, - "-", -) -plt.legend() -plt.show() - -plt.plot(x, y - fit, "o", label="residuals") -plt.axhline(0, color="k", ls="--") -plt.legend() -plt.show() From 22f92332b0526aa229d0d61980a41183c3a79177 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 14:28:44 +0000 Subject: [PATCH 44/52] removing some debug print statements --- maxsmooth/qp.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index b5d6835..f6ae976 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -270,10 +270,6 @@ def body_unique_flip(i: int, fs: jnp.ndarray) -> jnp.ndarray: visited_signs, ) - # jax.debug.print("Visited signs: {}", visited_signs) - # jax.debug.print("Number of flip signs to try: {}", len(flip_signs)) - # jax.debug.print("Flip signs: {}", flip_signs) - sol = vmapped_dcf(flip_signs, c, Q) minimum_index = jnp.argmin(jnp.array(sol.state.error)) return ( From 3878569e00d623423f87a4c7201082bf2b359483 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 14:32:55 +0000 Subject: [PATCH 45/52] layout the new docs --- .readthedocs.yml | 23 ++-- README.md | 116 +++++++++++++++++++ README.rst | 257 ------------------------------------------ docs/api-reference.md | 0 docs/index.md | 1 + docs/tutorials.md | 0 mkdocs.yml | 36 ++++++ pyproject.toml | 16 ++- 8 files changed, 180 insertions(+), 269 deletions(-) create mode 100644 README.md delete mode 100644 README.rst create mode 100644 docs/api-reference.md create mode 100644 docs/index.md create mode 100644 docs/tutorials.md create mode 100644 mkdocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml index 61b55e3..44221d2 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,18 +1,21 @@ # Required version: 2 -# Build documentation in the docs/ directory with Sphinx -sphinx: - configuration: docs/source/conf.py - fail_on_warning: false +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with MkDocs +mkdocs: + configuration: mkdocs.yaml -# Optionally build your docs in additional formats such as PDF and ePub -formats: - - htmlzip # Optionally set the version of Python and requirements required to build your docs python: - version: 3.8 install: - - requirements: docs/requirements.txt - - requirements: requirements.txt + - method : pip + path : . + extra_requirements : + - docs \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..cfba632 --- /dev/null +++ b/README.md @@ -0,0 +1,116 @@ +# maxsmooth: Derivative Constrained Function Fitting + +## Introduction + +**maxsmooth:** Derivative Constrained Function Fitting +**Author:** Harry Thomas Jones Bevins +**Version:** 2.0.0 +**Homepage:** https://github.com/htjb/maxsmooth +**Documentation:** https://maxsmooth.readthedocs.io/ + +![github CI](https://github.com/htjb/maxsmooth/workflows/CI/badge.svg?event=push) +![Test Coverage Status](https://codecov.io/gh/htjb/maxsmooth/branch/master/graph/badge.svg) +![Documentation Status](https://readthedocs.org/projects/maxsmooth/badge/?version=latest) +![License](https://img.shields.io/badge/license-MIT-blue.svg) +![PyPI](https://pypi.in/v/maxsmooth/badge.svg) +![ASCL](https://img.shields.io/badge/ascl-2008.018-blue.svg?colorB=262255) +![JOSS](https://joss.theoj.org/papers/7f53a67e2a3e8f021d4324de96fb59c8/status.svg) + +## Installation + +The software can be pip installed from the PYPI repository like so: + +```bash +pip install maxsmooth +``` + +or alternatively it can be installed from the git repository via: + +```bash +git clone https://github.com/htjb/maxsmooth.git +cd maxsmooth +pip install . +``` + +## Derivative Constrained Functions and `maxsmooth` + +`maxsmooth` is open source Python software (Python 3+) for fitting derivative constrained functions (DCFs) such as Maximally Smooth Functions (MSFs) to data sets. + +MSFs are functions with no zero crossings in derivatives of order m ≥ 2 within the domain of interest. More generally, for DCFs the minimum constrained derivative order m can take on any value or a set of specific higher order derivatives may be constrained. + +They are designed to prevent the loss of signals when fitting out dominant smooth foregrounds or large magnitude signals that mask signals of interest. “Smooth” here refers to foregrounds that follow power-law structures in the band of interest. In some cases DCFs can highlight systematics in the data. + +`maxsmooth` uses quadratic programming via `CVXOPT` to fit data subject to a fixed linear constraint, Ga ≤ 0, where Ga is a matrix of derivatives. The constraint on an MSF is not explicitly linear and each constrained derivative can be positive or negative. `maxsmooth` tests the ≤ 0 constraint multiplied by a positive or negative sign. + +For an Nth-order polynomial `maxsmooth` can test every available sign combination, but by default it implements a sign navigating algorithm. This is detailed in the `maxsmooth` paper and summarized in the software documentation. + +The available sign combinations act as discrete parameter spaces all with global minima, and `maxsmooth` is capable of finding the minimum of these by cascading followed by directional exploration. The searched region is limited to capture enough of the neighbourhood to confidently return the global minimum. + +The method relies on the problem being “well defined”, but not all problems satisfy this. In such cases it is possible to test every available sign combination on the constrained derivatives. See the paper for definitions. + +`maxsmooth` features a built-in library of DCFs and allows users to define their own. Inflection points and zero crossings in higher order derivatives can also be included. + +## Licence and Citation + +The software is free to use under the MIT open source license. For academic use please cite the `maxsmooth` papers: + +**MNRAS Paper (the “maxsmooth paper”):** + +> H. T. J. Bevins et al., *maxsmooth: Rapid maximally smooth function fitting with applications in Global 21-cm cosmology*, MNRAS, 2021, stab152. https://doi.org/10.1093/mnras/stab152 + +BibTeX: + +```bibtex +@article{10.1093/mnras/stab152, + author = {Bevins, H T J and Handley, W J and Fialkov, A and Acedo, E de Lera and Greenhill, L J and Price, D C}, + title = "{maxsmooth: rapid maximally smooth function fitting with applications in Global 21-cm cosmology}", + journal = {Monthly Notices of the Royal Astronomical Society}, + year = {2021}, + month = {01}, + issn = {0035-8711}, + doi = {10.1093/mnras/stab152}, + url = {https://doi.org/10.1093/mnras/stab152}, + note = {stab152}, + eprint = {https://academic.oup.com/mnras/advance-article-pdf/doi/10.1093/mnras/stab152/35931358/stab152.pdf}, +} +``` + +**JOSS Paper:** + +> Bevins, H. T., (2020). *maxsmooth: Derivative Constrained Function Fitting*, Journal of Open Source Software, 5(54), 2596. https://doi.org/10.21105/joss.02596 + +BibTeX: + +```bibtex +@article{Bevins2020, + doi = {10.21105/joss.02596}, + url = {https://doi.org/10.21105/joss.02596}, + year = {2020}, + publisher = {The Open Journal}, + volume = {5}, + number = {54}, + pages = {2596}, + author = {Harry T. j. Bevins}, + title = {maxsmooth: Derivative Constrained Function Fitting}, + journal = {Journal of Open Source Software} +} +``` + +## Contributing + +Contributions to `maxsmooth` are welcome via: + +- Opening an issue for new features or bugs. +- Submitting a pull request (ideally with prior discussion). + +## Documentation + +Documentation: https://maxsmooth.readthedocs.io/ + +You can also compile it locally by running + +```bash +pip install ".[docs]" +mkdocs serve +``` + diff --git a/README.rst b/README.rst deleted file mode 100644 index 794e237..0000000 --- a/README.rst +++ /dev/null @@ -1,257 +0,0 @@ -================================================== -maxsmooth: Derivative Constrained Function Fitting -================================================== - -Introduction ------------- - -:maxsmooth: Derivative Constrained Function Fitting -:Author: Harry Thomas Jones Bevins -:Version: 1.2.1 -:Homepage: https://github.com/htjb/maxsmooth -:Documentation: https://maxsmooth.readthedocs.io/ - -.. image:: https://github.com/htjb/maxsmooth/workflows/CI/badge.svg?event=push - :target: https://github.com/htjb/maxsmooth/actions - :alt: github CI -.. image:: https://codecov.io/gh/htjb/maxsmooth/branch/master/graph/badge.svg - :target: https://codecov.io/gh/htjb/maxsmooth - :alt: Test Coverage Status -.. image:: https://readthedocs.org/projects/maxsmooth/badge/?version=latest - :target: https://maxsmooth.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status -.. image:: https://img.shields.io/badge/license-MIT-blue.svg - :target: https://github.com/htjb/maxsmooth/blob/master/LICENSE - :alt: License information -.. image:: https://pypip.in/v/maxsmooth/badge.svg - :target: https://pypi.org/project/maxsmooth/#description - :alt: Latest PyPI version -.. image:: https://img.shields.io/badge/ascl-2008.018-blue.svg?colorB=262255 - :target: http://ascl.net/2008.018 - :alt: Astrophysics Source Code Library -.. image:: https://joss.theoj.org/papers/7f53a67e2a3e8f021d4324de96fb59c8/status.svg - :target: https://joss.theoj.org/papers/7f53a67e2a3e8f021d4324de96fb59c8 - :alt: JOSS paper -.. image:: https://mybinder.org/badge_logo.svg - :target: https://mybinder.org/v2/gh/htjb/maxsmooth/master?filepath=example_notebooks%2F -.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.4059339.svg - :target: https://doi.org/10.5281/zenodo.4059339 - -Installation -~~~~~~~~~~~~ -In the following two sections we highlight the purpose of ``maxsmooth`` and -show an example. To install the software follow these instructions: - -The software can be pip installed from the PYPI repository like so, - -.. code:: - - pip install maxsmooth - -or alternatively it can be installed from the git repository via, - -.. code:: - - git clone https://github.com/htjb/maxsmooth.git - cd maxsmooth - python setup.py install --user - -Derivative Constrained Functions and ``maxsmooth`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``maxsmooth`` is an open source software, written in Python (supporting version 3 upwards), -for fitting derivative constrained -functions (DCFs) such as Maximally Smooth Functions -(MSFs) to data sets. MSFs are functions for which there are no zero -crossings in derivatives of order m >= 2 within the domain of interest. -More generally for DCFs the minimum -constrained derivative order, m can take on any value or a set of -specific high order derivatives can be constrained. -They are designed to prevent the loss of -signals when fitting out dominant smooth foregrounds or large magnitude signals that -mask signals of interest. Here "smooth" means that the foregrounds follow power -law structures in the band of interest. -In some cases DCFs can be used to -highlight systematics in the data. - -``maxsmooth`` uses quadratic programming implemented with ``CVXOPT`` to fit -data subject to a fixed linear constraint, Ga <= 0, where the product -Ga is a matrix of derivatives. -The constraint on an MSF are not explicitly -linear and each constrained derivative can be positive or negative. -``maxsmooth`` is, however, designed to test the <= 0 constraint multiplied -by a positive or negative sign. Where a positive sign in front of the m\ :sup:`th` -order derivative forces the derivative -to be negative for all x. For an N\ :sup:`th` order polynomial ``maxsmooth`` can test -every available sign combination but by default it implements a sign navigating algorithm. -This is detailed in the ``maxsmooth`` paper (see citation), is summarized -below and in the software documentation. - -The available sign combinations act as discrete parameter spaces all with -global minima and ``maxsmooth`` is capable of finding the minimum of these global -minima by implementing a cascading algorithm which is followed by a directional -exploration. The cascading routine typically finds an approximate to the global -minimum and then the directional exploration is a complete search -of the sign combinations in the neighbourhood -of that minimum. The searched region is limited by factors -that encapsulate enough of the neighbourhood to confidently return the global minimum. - -The sign navigating method is reliant on the problem being "well defined" but this -is not always the case and it is in these instances it is possible to run the code testing -every available sign combination on the constrained derivatives. For a definition of -a "well defined" problem and it's counter part see the ``maxsmooth`` paper and the -documentation. - -``maxsmooth`` features a built in library of DCFs or -allows the user to define their own. The addition of possible inflection points -and zero crossings in higher order derivatives is also available to the user. -The software has been designed with these two -applications in mind and is a simple interface. - -Example Fit -~~~~~~~~~~~ - -Shown below is an example MSF fit performed with ``maxsmooth`` to data that -follows a y = x\ :sup:`-2.5` power law with a randomly generated Gaussian -noise with a standard deviation 0.02. The top panel shows the data and the -bottom panel shows the residual -after subtraction of the MSF fit alongside the actual noise in the data. -The software using the default built-in DCF model is shown to be -capable of recovering the random noise. - -.. image:: https://github.com/htjb/maxsmooth/raw/master/docs/images/README.png - :width: 400 - :align: center - -Further examples can be found in the Documentation (https://maxsmooth.readthedocs.io/) -and in the github repository in the files 'example_codes/' and -'example_notebooks/' (notebooks can also be accessed online -`here `__). - -Licence and Citation -~~~~~~~~~~~~~~~~~~~~ - -The software is free to use on the MIT open source license. However if you use -the software for academic purposes we request that you cite the ``maxsmooth`` -papers. They are detailed below. - -MNRAS paper (referred to throughout the documentation as the ``maxsmooth`` -paper), - - H. T. J. Bevins et al., `maxsmooth: Rapid maximally smooth function fitting with - applications in Global 21-cm cosmology `__, - Monthly Notices of the Royal Astronomical Society, 2021;, stab152, https://doi.org/10.1093/mnras/stab152 - -Below is the BibTex citation, - -.. code:: bibtex - - @article{10.1093/mnras/stab152, - author = {Bevins, H T J and Handley, W J and Fialkov, A and Acedo, E de Lera and Greenhill, L J and Price, D C}, - title = "{maxsmooth: rapid maximally smooth function fitting with applications in Global 21-cm cosmology}", - journal = {Monthly Notices of the Royal Astronomical Society}, - year = {2021}, - month = {01}, - issn = {0035-8711}, - doi = {10.1093/mnras/stab152}, - url = {https://doi.org/10.1093/mnras/stab152}, - note = {stab152}, - eprint = {https://academic.oup.com/mnras/advance-article-pdf/doi/10.1093/mnras/stab152/35931358/stab152.pdf}, - } - -JOSS paper, - - Bevins, H. T., (2020). maxsmooth: Derivative Constrained Function Fitting. Journal of Open Source Software, 5(54), 2596, https://doi.org/10.21105/joss.02596 - -and the BibTex, - -.. code:: bibtex - - @article{Bevins2020, - doi = {10.21105/joss.02596}, - url = {https://doi.org/10.21105/joss.02596}, - year = {2020}, - publisher = {The Open Journal}, - volume = {5}, - number = {54}, - pages = {2596}, - author = {Harry T. j. Bevins}, - title = {maxsmooth: Derivative Constrained Function Fitting}, - journal = {Journal of Open Source Software} - } - - -Contributing -~~~~~~~~~~~~ - -Contributions to ``maxsmooth`` are welcome and can be made via: - -- Opening an issue to purpose new features/report bugs. -- Making a pull request. Please consider opening an issue to discuss - any proposals beforehand and ensure that your PR will be accepted. - -An example contribution may be the addition of a basis function into the -standard library. - -Documentation -~~~~~~~~~~~~~ -The documentation is available at: https://maxsmooth.readthedocs.io/ - -Alternatively, it can be compiled locally from the git repository and requires -`sphinx `__ to be installed. -You can do this via: - -.. code:: - - cd docs/ - make SOURCEDIR=source html - -or - -.. code:: - - cd docs/ - make SOURCEDIR=source latexpdf - -The resultant docs can be found in the docs/_build/html/ and docs/_build/latex/ -respectively. - -Requirements -~~~~~~~~~~~~ - -To run the code you will need the following additional packages: - -- `matplotlib `__ -- `numpy `__ -- `CVXOPT `__ -- `scipy `__ -- `progressbar `__ - -When installing via pip or from source using the setup.py file -the above packages will also be installed if absent. - -To compile the documentation locally you will need: - -- `sphinx `__ -- `numpydoc `__ - -To run the test suit you will need: - -- `pytest `__ - -Basin-hopping/Nelder-Mead Code -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In the ``maxsmooth`` MNRAS paper and JOSS paper we provide a comparison of -``maxsmooth`` to a Basin-hopping/Nelder-Mead approach for fitting DCFs. For -completeness we provide in this repo the code used to make this comparison -in the file 'Basin-hopping_Nelder_Mead/'. - -The code times_chis.py is used to call ``maxsmooth`` and the Basin-hopping -methods (in the file 'BHNM/'). It will plot the recorded times and objective -function evaluations. - -The Basin-hopping/Nelder-Mead code is designed to fit MSFs and is not -generalised to all types of DCF. It is also not documented, however there are -minor comments in the script and it should be self explanatory. Questions -on this are welcome and can be posted as an issue or by contacting the author. diff --git a/docs/api-reference.md b/docs/api-reference.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..96d83c6 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +{% include-markdown "../README.md" %} \ No newline at end of file diff --git a/docs/tutorials.md b/docs/tutorials.md new file mode 100644 index 0000000..e69de29 diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..8466a87 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,36 @@ +site_name: maxsmooth +theme: + name: material + features: + - navigation.sections + - navigation.top + - search.highlight + - search.suggestions + palette: + - scheme: default + primary: blue + toggle: + icon: material/weather-night + name: Switch to dark mode + - scheme: slate + primary: blue + toggle: + icon: material/weather-sunny + name: Switch to light mode +plugins: + - include-markdown + - search + - mkdocstrings: + handlers: + python: + paths: [maxsmooth] + options: + show_root_heading: true + heading_level: 2 +markdown_extensions: + - pymdownx.highlight + - pymdownx.superfences +nav: + - Home: index.md + - Tutorials: tutorials.md + - API Reference: api-reference.md \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 12a54ad..4cf44fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,8 +5,6 @@ description = "Add your description here" readme = "README.md" requires-python = ">=3.13" dependencies = [ - "cvxopt>=1.3.2", - "cvxpy>=1.7.3", "jax>=0.8.0", "jaxopt>=0.8.5", "matplotlib>=3.10.7", @@ -15,6 +13,20 @@ dependencies = [ "scipy>=1.16.3", ] +[project.optional-dependencies] +dev = [ + "pytest", + "ruff", + "pre-commit", +] +docs = [ + "mkdocs", + "mkdocs-material", + "mkdocstrings", + "mkdocstrings-python", + "mkdocs-include-markdown-plugin", + "pymdown-extensions", +] [tool.ruff] line-length = 79 From 5e0dffbfa4719038345bfb68d0bb6663a8aa4399 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 14:33:43 +0000 Subject: [PATCH 46/52] deleting uv files --- .python-version | 1 - uv.lock | 770 ------------------------------------------------ 2 files changed, 771 deletions(-) delete mode 100644 .python-version delete mode 100644 uv.lock diff --git a/.python-version b/.python-version deleted file mode 100644 index 24ee5b1..0000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.13 diff --git a/uv.lock b/uv.lock deleted file mode 100644 index 5216005..0000000 --- a/uv.lock +++ /dev/null @@ -1,770 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.13" - -[[package]] -name = "cffi" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, - { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, - { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, - { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, - { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, - { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, - { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, - { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, - { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, - { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, - { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, - { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, - { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, - { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, - { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, - { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, - { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, - { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, - { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, - { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, - { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, - { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, - { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, -] - -[[package]] -name = "clarabel" -version = "0.11.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi" }, - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/81/e2/47f692161779dbd98876015de934943effb667a014e6f79a6d746b3e4c2a/clarabel-0.11.1.tar.gz", hash = "sha256:e7c41c47f0e59aeab99aefff9e58af4a8753ee5269bbeecbd5526fc6f41b9598", size = 253949, upload-time = "2025-06-11T16:49:05.864Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/f7/f82698b6d00a40a80c67e9a32b2628886aadfaf7f7b32daa12a463e44571/clarabel-0.11.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c39160e4222040f051f2a0598691c4f9126b4d17f5b9e7678f76c71d611e12d8", size = 1039511, upload-time = "2025-06-11T16:48:58.525Z" }, - { url = "https://files.pythonhosted.org/packages/b0/8f/13650cfe25762b51175c677330e6471d5d2c5851a6fbd6df77f0681bb34e/clarabel-0.11.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8963687ee250d27310d139eea5a6816f9c3ae31f33691b56579ca4f0f0b64b63", size = 935135, upload-time = "2025-06-11T16:48:59.901Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9e/7af10d2b540b39f1a05d1ebba604fce933cc9bc0e65e88ec3b7a84976425/clarabel-0.11.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4837b9d0db01e98239f04b1e3526a6cf568529d3c19a8b3f591befdc467f9bb", size = 1079226, upload-time = "2025-06-11T16:49:00.987Z" }, - { url = "https://files.pythonhosted.org/packages/6b/a9/c76edf781ca3283186ff4b54a9a4fb51367fd04313a68e2b09f062407439/clarabel-0.11.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8c41aaa6f3f8c0f3bd9d86c3e568dcaee079562c075bd2ec9fb3a80287380ef", size = 1164345, upload-time = "2025-06-11T16:49:02.675Z" }, - { url = "https://files.pythonhosted.org/packages/41/e6/4eee3062088c221e5a18b054e51c69f616e0bb0dc1b0a1a5e0fe90dfa18e/clarabel-0.11.1-cp39-abi3-win_amd64.whl", hash = "sha256:557d5148a4377ae1980b65d00605ae870a8f34f95f0f6a41e04aa6d3edf67148", size = 887310, upload-time = "2025-06-11T16:49:04.277Z" }, -] - -[[package]] -name = "contourpy" -version = "1.3.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, - { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, - { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, - { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, - { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, - { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, - { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, - { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, - { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, - { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, - { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, - { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, - { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, - { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, - { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, - { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, - { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, - { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, - { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, - { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, - { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, - { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, - { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, - { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, - { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, - { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, - { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, - { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, - { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, - { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, - { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, - { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, - { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, - { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, - { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, - { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, - { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, - { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, - { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, - { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, -] - -[[package]] -name = "cvxopt" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/12/8467d16008ab7577259d32f1e59c4d84edda22b7729ab4a1a0dfd5f0550b/cvxopt-1.3.2.tar.gz", hash = "sha256:3461fa42c1b2240ba4da1d985ca73503914157fc4c77417327ed6d7d85acdbe6", size = 4108454, upload-time = "2023-08-09T14:31:17.514Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/c5/3e70e50c4c478acd3fefe3ea51b7e42ad661ce5a265a72b3dba175ce10fc/cvxopt-1.3.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:2f9135eea23c9b781574e0cadc5738cf5651a8fd8de822b6de1260411523bfd1", size = 16873224, upload-time = "2024-10-21T20:48:37.221Z" }, - { url = "https://files.pythonhosted.org/packages/61/96/e42b9ec38e1bbe9bf85a5fc9cc7feb173de5a874889735072b49a7d4d8d0/cvxopt-1.3.2-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:d7921768712db156e6ec92ac21f7ce52069feb1fb994868d0ca795498111fbac", size = 12424739, upload-time = "2024-10-21T20:48:40.325Z" }, - { url = "https://files.pythonhosted.org/packages/32/08/2c621ad782e9ff7f921c2244c6b4bcbc72ca756cb33021295c288123c465/cvxopt-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af63db45ba559e3e15180fbec140d8a4ff612d8f21d989181a4e8479fa3b8b6", size = 17869707, upload-time = "2024-10-21T20:48:42.881Z" }, - { url = "https://files.pythonhosted.org/packages/62/60/583a1ef8e2e259bdd1bf32fccd4ea15aef4aad5854746ec59cbb2462eb92/cvxopt-1.3.2-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:8fe178ac780a8bccf425a08004d853eae43b3ddcf7617521fb35c63550077b17", size = 13846614, upload-time = "2024-10-21T20:48:46.26Z" }, - { url = "https://files.pythonhosted.org/packages/e4/2b/d8721b046a3c8bff494490a01ef1eeacf1f970f0d1274448856ccbe0475c/cvxopt-1.3.2-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a47a95d7848e6fe768b55910bac8bb114c5f1f355f5a6590196d5e9bdf775d2f", size = 21277032, upload-time = "2024-10-21T20:48:49.48Z" }, - { url = "https://files.pythonhosted.org/packages/6a/19/b1e1c16895a36cc504bf7a940e88431b82b18ca10cbce81072860b9e3d60/cvxopt-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e863238d64a4b4443b8be53a08f6b94eda6ec1727038c330da02014f7c19e1be", size = 9530674, upload-time = "2024-10-21T20:48:51.948Z" }, - { url = "https://files.pythonhosted.org/packages/42/cc/ac0705749f96cc52f8d30c9c06e54dc8d4c04ef9c2d21aeed1ae2ee63dab/cvxopt-1.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c56965415afd8a493cc4af3587960751f8780057ca3de8c6be97217156e4633", size = 13725340, upload-time = "2024-10-21T20:48:55.074Z" }, - { url = "https://files.pythonhosted.org/packages/76/f2/7e3c3f51e8e6b325bf00bfc37036f1f58bd9a5c29bbd88fb2eef2ebc0ac2/cvxopt-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:85c3b52c1353b294c597b169cc901f5274d8bb8776908ccad66fec7a14b69519", size = 16226402, upload-time = "2024-10-21T20:48:57.616Z" }, - { url = "https://files.pythonhosted.org/packages/b9/55/90b40b489a235a9f35a532eb77cec81782e466779d9a531ffda6b2f99410/cvxopt-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:0a0987966009ad383de0918e61255d34ed9ebc783565bcb15470d4155010b6bf", size = 12845323, upload-time = "2024-10-21T20:49:00.581Z" }, -] - -[[package]] -name = "cvxpy" -version = "1.7.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "clarabel" }, - { name = "numpy" }, - { name = "osqp" }, - { name = "scipy" }, - { name = "scs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/cf/583d8c25bf1ec8d43e0f9953fa3d48f095022dc2fc7e7a437ebdeaf16d9f/cvxpy-1.7.3.tar.gz", hash = "sha256:241d364f5962a1d68c4ae8393480766a09326e5771e2286d33a948e1976cbe70", size = 1635660, upload-time = "2025-09-22T18:21:42.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/9f/a66cd862fdcca0027a8b902079d6a2ce86848b9f38a1c6e80bfdc8f72964/cvxpy-1.7.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:052db7e5485d3cbe6b0249c4cc0fec898cdfafcb8d2490149a21bd9a7d00a82f", size = 1538061, upload-time = "2025-09-22T18:02:30.573Z" }, - { url = "https://files.pythonhosted.org/packages/b2/9f/0bf93d696e6e75ae42e40915abb38ecae4a3b27f6cb52765415b012fda70/cvxpy-1.7.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a97e4e3eff4e9f8151058fe7687c7eecfb44b6a1ae83834195b701088ce29e7", size = 1193747, upload-time = "2025-09-22T18:02:32.024Z" }, - { url = "https://files.pythonhosted.org/packages/48/55/1542a643403cd57adf83e27243dc2a057fb4fab03f38f5de3cb0327e468a/cvxpy-1.7.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cfed5afe3d53fc7835ea8cc9e281d0bbf3b4edcc625e8a1162c42cb807b8830d", size = 1204232, upload-time = "2025-09-22T18:22:27.222Z" }, - { url = "https://files.pythonhosted.org/packages/f8/bf/9b5b5abcf06038eea8826d440c5c24c1f32c7339c750f0b705d2fe4cdafc/cvxpy-1.7.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d8b2213296478478d267537681f96ea7d9941d5bb1fa61717797f9fabd3b747", size = 1233261, upload-time = "2025-09-22T18:22:28.709Z" }, - { url = "https://files.pythonhosted.org/packages/02/ca/4648ad361e0060834104672c2ce0d6a96996f374e83615fc69a87b1e3841/cvxpy-1.7.3-cp313-cp313-win_amd64.whl", hash = "sha256:d1def84c970a8a5765849e225732c6308c1bba8900bbfa7d4a17ea955e82ce80", size = 1131760, upload-time = "2025-09-22T18:01:04.595Z" }, -] - -[[package]] -name = "cycler" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, -] - -[[package]] -name = "fonttools" -version = "4.60.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4b/42/97a13e47a1e51a5a7142475bbcf5107fe3a68fc34aef331c897d5fb98ad0/fonttools-4.60.1.tar.gz", hash = "sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9", size = 3559823, upload-time = "2025-09-29T21:13:27.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/5b/cdd2c612277b7ac7ec8c0c9bc41812c43dc7b2d5f2b0897e15fdf5a1f915/fonttools-4.60.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb", size = 2825777, upload-time = "2025-09-29T21:12:01.22Z" }, - { url = "https://files.pythonhosted.org/packages/d6/8a/de9cc0540f542963ba5e8f3a1f6ad48fa211badc3177783b9d5cadf79b5d/fonttools-4.60.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4", size = 2348080, upload-time = "2025-09-29T21:12:03.785Z" }, - { url = "https://files.pythonhosted.org/packages/2d/8b/371ab3cec97ee3fe1126b3406b7abd60c8fec8975fd79a3c75cdea0c3d83/fonttools-4.60.1-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c", size = 4903082, upload-time = "2025-09-29T21:12:06.382Z" }, - { url = "https://files.pythonhosted.org/packages/04/05/06b1455e4bc653fcb2117ac3ef5fa3a8a14919b93c60742d04440605d058/fonttools-4.60.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77", size = 4960125, upload-time = "2025-09-29T21:12:09.314Z" }, - { url = "https://files.pythonhosted.org/packages/8e/37/f3b840fcb2666f6cb97038793606bdd83488dca2d0b0fc542ccc20afa668/fonttools-4.60.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199", size = 4901454, upload-time = "2025-09-29T21:12:11.931Z" }, - { url = "https://files.pythonhosted.org/packages/fd/9e/eb76f77e82f8d4a46420aadff12cec6237751b0fb9ef1de373186dcffb5f/fonttools-4.60.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c", size = 5044495, upload-time = "2025-09-29T21:12:15.241Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b3/cede8f8235d42ff7ae891bae8d619d02c8ac9fd0cfc450c5927a6200c70d/fonttools-4.60.1-cp313-cp313-win32.whl", hash = "sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272", size = 2217028, upload-time = "2025-09-29T21:12:17.96Z" }, - { url = "https://files.pythonhosted.org/packages/75/4d/b022c1577807ce8b31ffe055306ec13a866f2337ecee96e75b24b9b753ea/fonttools-4.60.1-cp313-cp313-win_amd64.whl", hash = "sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac", size = 2266200, upload-time = "2025-09-29T21:12:20.14Z" }, - { url = "https://files.pythonhosted.org/packages/9a/83/752ca11c1aa9a899b793a130f2e466b79ea0cf7279c8d79c178fc954a07b/fonttools-4.60.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3", size = 2822830, upload-time = "2025-09-29T21:12:24.406Z" }, - { url = "https://files.pythonhosted.org/packages/57/17/bbeab391100331950a96ce55cfbbff27d781c1b85ebafb4167eae50d9fe3/fonttools-4.60.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85", size = 2345524, upload-time = "2025-09-29T21:12:26.819Z" }, - { url = "https://files.pythonhosted.org/packages/3d/2e/d4831caa96d85a84dd0da1d9f90d81cec081f551e0ea216df684092c6c97/fonttools-4.60.1-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537", size = 4843490, upload-time = "2025-09-29T21:12:29.123Z" }, - { url = "https://files.pythonhosted.org/packages/49/13/5e2ea7c7a101b6fc3941be65307ef8df92cbbfa6ec4804032baf1893b434/fonttools-4.60.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003", size = 4944184, upload-time = "2025-09-29T21:12:31.414Z" }, - { url = "https://files.pythonhosted.org/packages/0c/2b/cf9603551c525b73fc47c52ee0b82a891579a93d9651ed694e4e2cd08bb8/fonttools-4.60.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08", size = 4890218, upload-time = "2025-09-29T21:12:33.936Z" }, - { url = "https://files.pythonhosted.org/packages/fd/2f/933d2352422e25f2376aae74f79eaa882a50fb3bfef3c0d4f50501267101/fonttools-4.60.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99", size = 4999324, upload-time = "2025-09-29T21:12:36.637Z" }, - { url = "https://files.pythonhosted.org/packages/38/99/234594c0391221f66216bc2c886923513b3399a148defaccf81dc3be6560/fonttools-4.60.1-cp314-cp314-win32.whl", hash = "sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6", size = 2220861, upload-time = "2025-09-29T21:12:39.108Z" }, - { url = "https://files.pythonhosted.org/packages/3e/1d/edb5b23726dde50fc4068e1493e4fc7658eeefcaf75d4c5ffce067d07ae5/fonttools-4.60.1-cp314-cp314-win_amd64.whl", hash = "sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987", size = 2270934, upload-time = "2025-09-29T21:12:41.339Z" }, - { url = "https://files.pythonhosted.org/packages/fb/da/1392aaa2170adc7071fe7f9cfd181a5684a7afcde605aebddf1fb4d76df5/fonttools-4.60.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299", size = 2894340, upload-time = "2025-09-29T21:12:43.774Z" }, - { url = "https://files.pythonhosted.org/packages/bf/a7/3b9f16e010d536ce567058b931a20b590d8f3177b2eda09edd92e392375d/fonttools-4.60.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01", size = 2375073, upload-time = "2025-09-29T21:12:46.437Z" }, - { url = "https://files.pythonhosted.org/packages/9b/b5/e9bcf51980f98e59bb5bb7c382a63c6f6cac0eec5f67de6d8f2322382065/fonttools-4.60.1-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801", size = 4849758, upload-time = "2025-09-29T21:12:48.694Z" }, - { url = "https://files.pythonhosted.org/packages/e3/dc/1d2cf7d1cba82264b2f8385db3f5960e3d8ce756b4dc65b700d2c496f7e9/fonttools-4.60.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc", size = 5085598, upload-time = "2025-09-29T21:12:51.081Z" }, - { url = "https://files.pythonhosted.org/packages/5d/4d/279e28ba87fb20e0c69baf72b60bbf1c4d873af1476806a7b5f2b7fac1ff/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc", size = 4957603, upload-time = "2025-09-29T21:12:53.423Z" }, - { url = "https://files.pythonhosted.org/packages/78/d4/ff19976305e0c05aa3340c805475abb00224c954d3c65e82c0a69633d55d/fonttools-4.60.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed", size = 4974184, upload-time = "2025-09-29T21:12:55.962Z" }, - { url = "https://files.pythonhosted.org/packages/63/22/8553ff6166f5cd21cfaa115aaacaa0dc73b91c079a8cfd54a482cbc0f4f5/fonttools-4.60.1-cp314-cp314t-win32.whl", hash = "sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259", size = 2282241, upload-time = "2025-09-29T21:12:58.179Z" }, - { url = "https://files.pythonhosted.org/packages/8a/cb/fa7b4d148e11d5a72761a22e595344133e83a9507a4c231df972e657579b/fonttools-4.60.1-cp314-cp314t-win_amd64.whl", hash = "sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c", size = 2345760, upload-time = "2025-09-29T21:13:00.375Z" }, - { url = "https://files.pythonhosted.org/packages/c7/93/0dd45cd283c32dea1545151d8c3637b4b8c53cdb3a625aeb2885b184d74d/fonttools-4.60.1-py3-none-any.whl", hash = "sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb", size = 1143175, upload-time = "2025-09-29T21:13:24.134Z" }, -] - -[[package]] -name = "jax" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jaxlib" }, - { name = "ml-dtypes" }, - { name = "numpy" }, - { name = "opt-einsum" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/22/1c/9baf805e6c969a1a7afeb37d359e8a10585e8b2621f103626998b42ae838/jax-0.8.0.tar.gz", hash = "sha256:0ea5a7be7068c25934450dfd87d7d80a18a5d30e0a53454e7aade525b23accd5", size = 2489031, upload-time = "2025-10-15T23:10:11.839Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/77/4e6c9a54247810eff8ac8a1af7dc1be0779b52df0d82f3fc8586061914f3/jax-0.8.0-py3-none-any.whl", hash = "sha256:d190158bc019756c6a0f6b3d5fc8783471fb407e6deaff559eaac60dd5ee850a", size = 2900279, upload-time = "2025-10-15T23:10:09.88Z" }, -] - -[[package]] -name = "jaxlib" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ml-dtypes" }, - { name = "numpy" }, - { name = "scipy" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/76/f11130a3a6318a50662be4ee8c7ab6e61f3f334978653243ebc9d6f5d0bb/jaxlib-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5fcf33a5639f8f164a473a9c78a1fa0b2e15ac3fcbecd6d96aa0f88bf25ea6bb", size = 54964169, upload-time = "2025-10-15T23:10:49.524Z" }, - { url = "https://files.pythonhosted.org/packages/24/2b/31ded3e83f3e198edc54519dc72cc829aa4875481ee6e19f123ef474f065/jaxlib-0.8.0-cp313-cp313-manylinux_2_27_aarch64.whl", hash = "sha256:b3eac503b90ffecc68f11fa122133eef2c62c536db28e801e436d7e7a9b67bf8", size = 73160932, upload-time = "2025-10-15T23:10:52.47Z" }, - { url = "https://files.pythonhosted.org/packages/8f/f0/cde1d84c737bdb75712f70d69561120ce91f3f294acf2fba573c0de740b6/jaxlib-0.8.0-cp313-cp313-manylinux_2_27_x86_64.whl", hash = "sha256:66c6f576f54a63ed052f5c469bef4db723f5f050b839ec0c429573011341bd58", size = 79698354, upload-time = "2025-10-15T23:10:55.822Z" }, - { url = "https://files.pythonhosted.org/packages/f1/be/88fa119a05525f7b683588b789c0e8f51292280dfcfbf7d0193bd3f7b651/jaxlib-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:72759ebbfb40a717349f174712207d306aa28630359f05cd69b091bd4efa0603", size = 59323012, upload-time = "2025-10-15T23:10:59.475Z" }, - { url = "https://files.pythonhosted.org/packages/88/c9/2eabf3126424625dc0390a5382b8911c494b7dd8e902aa7c9d5607259664/jaxlib-0.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df2781e0fc93fb6f42111b385b90126b9571eafe0e860f033615ff7156b76817", size = 55067941, upload-time = "2025-10-15T23:11:02.235Z" }, - { url = "https://files.pythonhosted.org/packages/72/7e/1d6ef4d730b381c382847e30e39b906d5bc7ba3c13c394c0412aa0a7261e/jaxlib-0.8.0-cp313-cp313t-manylinux_2_27_aarch64.whl", hash = "sha256:7eb3be931de77bfcde27df659ada432719aa1e19a2fa5b835638e7404c74cb63", size = 73278908, upload-time = "2025-10-15T23:11:05.299Z" }, - { url = "https://files.pythonhosted.org/packages/1f/3c/d1d424e5483a8bc5eba631892c58f6c6e738844195c065bc50e6506561c0/jaxlib-0.8.0-cp313-cp313t-manylinux_2_27_x86_64.whl", hash = "sha256:accebe89a36e28306a4db3f68f527a0f87b8a0fd253b3c1556fbd24f16bec22c", size = 79805682, upload-time = "2025-10-15T23:11:08.962Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/de0a3ab213a54e75207f9cb3bb48dfb87051dcee59a66955237452be1275/jaxlib-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ba7e8a2231e4138ccbd8e096debdbbcd82edc5fc1b13c66f32a51bc240651349", size = 54971716, upload-time = "2025-10-15T23:11:12.017Z" }, - { url = "https://files.pythonhosted.org/packages/83/a7/27b53c718aa5779749ebbc644d942b844f49e5527cb94d4a72119252c866/jaxlib-0.8.0-cp314-cp314-manylinux_2_27_aarch64.whl", hash = "sha256:a9bfca27ae597804db08694a2bf7e1cf7fc3fac4ac2e65ace83be8effaa927ea", size = 73181480, upload-time = "2025-10-15T23:11:15.395Z" }, - { url = "https://files.pythonhosted.org/packages/62/75/3f8fd3d40475ca13c35df382a5612a73ef0e7fa658ade521ffd6843d0573/jaxlib-0.8.0-cp314-cp314-manylinux_2_27_x86_64.whl", hash = "sha256:bd3219a4d2bfe4b72605900fde395b62126a053c0b99643eb931b7c20e577bf2", size = 79719384, upload-time = "2025-10-15T23:11:19.066Z" }, - { url = "https://files.pythonhosted.org/packages/c5/e5/633f5513c71d52d404d17931a14fb589303c4dca9de2d66b1eb029d98ed5/jaxlib-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3320a72d532713c2a31eb20d02c342540a0dec28603a3ac2be0fc0631f086cf2", size = 61572700, upload-time = "2025-10-15T23:11:24.769Z" }, - { url = "https://files.pythonhosted.org/packages/4d/04/5e7bb66dfb5115e3753ded81354c7bbda9a45f6c0e239faec391821ce974/jaxlib-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:248f1ac3acee1fe2cc81e8a668311f3ccb8f28090404391c276869cae8a95daf", size = 55065346, upload-time = "2025-10-15T23:11:28.121Z" }, - { url = "https://files.pythonhosted.org/packages/f5/a8/dba41b8f574c188ca30866562ebf06fa0558446e11565436ead5ad4d5fe4/jaxlib-0.8.0-cp314-cp314t-manylinux_2_27_aarch64.whl", hash = "sha256:a5f0656bbbb3f135a360ce0fde55bf34faf73fbc62ab887941e85f0014b3f476", size = 73276773, upload-time = "2025-10-15T23:11:31.067Z" }, - { url = "https://files.pythonhosted.org/packages/6c/82/774ff02e014ee12925388f7a77fe9beda6a8d08537666ce6259fc810b9f6/jaxlib-0.8.0-cp314-cp314t-manylinux_2_27_x86_64.whl", hash = "sha256:61cb2fde154e5a399db2880d560e3443cfa97bda9f074b545c886232ac8fe024", size = 79805953, upload-time = "2025-10-15T23:11:34.323Z" }, -] - -[[package]] -name = "jaxopt" -version = "0.8.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jax" }, - { name = "jaxlib" }, - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3a/da/ff7d7fbd13b8ed5e8458e80308d075fc649062b9f8676d3fc56f2dc99a82/jaxopt-0.8.5.tar.gz", hash = "sha256:2790bd68ef132b216c083a8bc7a2704eceb35a92c0fc0a1e652e79dfb1e9e9ab", size = 121709, upload-time = "2025-04-14T17:59:01.618Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/d8/55e0901103c93d57bab3b932294c216f0cbd49054187ce29f8f13808d530/jaxopt-0.8.5-py3-none-any.whl", hash = "sha256:ff221d1a86908ec759eb1e219ee1d12bf208a70707e961bf7401076fe7cf4d5e", size = 172434, upload-time = "2025-04-14T17:59:00.342Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "joblib" -version = "1.5.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, -] - -[[package]] -name = "kiwisolver" -version = "1.4.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" }, - { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" }, - { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" }, - { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" }, - { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" }, - { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" }, - { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" }, - { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" }, - { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" }, - { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" }, - { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" }, - { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" }, - { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" }, - { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" }, - { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" }, - { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" }, - { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" }, - { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" }, - { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" }, - { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" }, - { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" }, - { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" }, - { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" }, - { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" }, - { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" }, - { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" }, - { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" }, - { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" }, - { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" }, - { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" }, - { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" }, - { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" }, - { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" }, - { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" }, - { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" }, - { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" }, - { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" }, - { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" }, - { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" }, - { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" }, - { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" }, - { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" }, - { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" }, - { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" }, - { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" }, - { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, - { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, - { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, - { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, - { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, - { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, - { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, - { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, - { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, - { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, - { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, - { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, - { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, - { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, - { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, - { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, - { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, - { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, - { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, - { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, - { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, - { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, - { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, - { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, - { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, - { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, - { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, - { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, - { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, - { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, - { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, - { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, - { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, - { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, - { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, - { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, -] - -[[package]] -name = "matplotlib" -version = "3.10.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/e2/d2d5295be2f44c678ebaf3544ba32d20c1f9ef08c49fe47f496180e1db15/matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7", size = 34804865, upload-time = "2025-10-09T00:28:00.669Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/9c/207547916a02c78f6bdd83448d9b21afbc42f6379ed887ecf610984f3b4e/matplotlib-3.10.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1d9d3713a237970569156cfb4de7533b7c4eacdd61789726f444f96a0d28f57f", size = 8273212, upload-time = "2025-10-09T00:26:56.752Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d0/b3d3338d467d3fc937f0bb7f256711395cae6f78e22cef0656159950adf0/matplotlib-3.10.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37a1fea41153dd6ee061d21ab69c9cf2cf543160b1b85d89cd3d2e2a7902ca4c", size = 8128713, upload-time = "2025-10-09T00:26:59.001Z" }, - { url = "https://files.pythonhosted.org/packages/22/ff/6425bf5c20d79aa5b959d1ce9e65f599632345391381c9a104133fe0b171/matplotlib-3.10.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b3c4ea4948d93c9c29dc01c0c23eef66f2101bf75158c291b88de6525c55c3d1", size = 8698527, upload-time = "2025-10-09T00:27:00.69Z" }, - { url = "https://files.pythonhosted.org/packages/d0/7f/ccdca06f4c2e6c7989270ed7829b8679466682f4cfc0f8c9986241c023b6/matplotlib-3.10.7-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22df30ffaa89f6643206cf13877191c63a50e8f800b038bc39bee9d2d4957632", size = 9529690, upload-time = "2025-10-09T00:27:02.664Z" }, - { url = "https://files.pythonhosted.org/packages/b8/95/b80fc2c1f269f21ff3d193ca697358e24408c33ce2b106a7438a45407b63/matplotlib-3.10.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b69676845a0a66f9da30e87f48be36734d6748024b525ec4710be40194282c84", size = 9593732, upload-time = "2025-10-09T00:27:04.653Z" }, - { url = "https://files.pythonhosted.org/packages/e1/b6/23064a96308b9aeceeffa65e96bcde459a2ea4934d311dee20afde7407a0/matplotlib-3.10.7-cp313-cp313-win_amd64.whl", hash = "sha256:744991e0cc863dd669c8dc9136ca4e6e0082be2070b9d793cbd64bec872a6815", size = 8122727, upload-time = "2025-10-09T00:27:06.814Z" }, - { url = "https://files.pythonhosted.org/packages/b3/a6/2faaf48133b82cf3607759027f82b5c702aa99cdfcefb7f93d6ccf26a424/matplotlib-3.10.7-cp313-cp313-win_arm64.whl", hash = "sha256:fba2974df0bf8ce3c995fa84b79cde38326e0f7b5409e7a3a481c1141340bcf7", size = 7992958, upload-time = "2025-10-09T00:27:08.567Z" }, - { url = "https://files.pythonhosted.org/packages/4a/f0/b018fed0b599bd48d84c08794cb242227fe3341952da102ee9d9682db574/matplotlib-3.10.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:932c55d1fa7af4423422cb6a492a31cbcbdbe68fd1a9a3f545aa5e7a143b5355", size = 8316849, upload-time = "2025-10-09T00:27:10.254Z" }, - { url = "https://files.pythonhosted.org/packages/b0/b7/bb4f23856197659f275e11a2a164e36e65e9b48ea3e93c4ec25b4f163198/matplotlib-3.10.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e38c2d581d62ee729a6e144c47a71b3f42fb4187508dbbf4fe71d5612c3433b", size = 8178225, upload-time = "2025-10-09T00:27:12.241Z" }, - { url = "https://files.pythonhosted.org/packages/62/56/0600609893ff277e6f3ab3c0cef4eafa6e61006c058e84286c467223d4d5/matplotlib-3.10.7-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:786656bb13c237bbcebcd402f65f44dd61ead60ee3deb045af429d889c8dbc67", size = 8711708, upload-time = "2025-10-09T00:27:13.879Z" }, - { url = "https://files.pythonhosted.org/packages/d8/1a/6bfecb0cafe94d6658f2f1af22c43b76cf7a1c2f0dc34ef84cbb6809617e/matplotlib-3.10.7-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09d7945a70ea43bf9248f4b6582734c2fe726723204a76eca233f24cffc7ef67", size = 9541409, upload-time = "2025-10-09T00:27:15.684Z" }, - { url = "https://files.pythonhosted.org/packages/08/50/95122a407d7f2e446fd865e2388a232a23f2b81934960ea802f3171518e4/matplotlib-3.10.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d0b181e9fa8daf1d9f2d4c547527b167cb8838fc587deabca7b5c01f97199e84", size = 9594054, upload-time = "2025-10-09T00:27:17.547Z" }, - { url = "https://files.pythonhosted.org/packages/13/76/75b194a43b81583478a81e78a07da8d9ca6ddf50dd0a2ccabf258059481d/matplotlib-3.10.7-cp313-cp313t-win_amd64.whl", hash = "sha256:31963603041634ce1a96053047b40961f7a29eb8f9a62e80cc2c0427aa1d22a2", size = 8200100, upload-time = "2025-10-09T00:27:20.039Z" }, - { url = "https://files.pythonhosted.org/packages/f5/9e/6aefebdc9f8235c12bdeeda44cc0383d89c1e41da2c400caf3ee2073a3ce/matplotlib-3.10.7-cp313-cp313t-win_arm64.whl", hash = "sha256:aebed7b50aa6ac698c90f60f854b47e48cd2252b30510e7a1feddaf5a3f72cbf", size = 8042131, upload-time = "2025-10-09T00:27:21.608Z" }, - { url = "https://files.pythonhosted.org/packages/0d/4b/e5bc2c321b6a7e3a75638d937d19ea267c34bd5a90e12bee76c4d7c7a0d9/matplotlib-3.10.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d883460c43e8c6b173fef244a2341f7f7c0e9725c7fe68306e8e44ed9c8fb100", size = 8273787, upload-time = "2025-10-09T00:27:23.27Z" }, - { url = "https://files.pythonhosted.org/packages/86/ad/6efae459c56c2fbc404da154e13e3a6039129f3c942b0152624f1c621f05/matplotlib-3.10.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07124afcf7a6504eafcb8ce94091c5898bbdd351519a1beb5c45f7a38c67e77f", size = 8131348, upload-time = "2025-10-09T00:27:24.926Z" }, - { url = "https://files.pythonhosted.org/packages/a6/5a/a4284d2958dee4116359cc05d7e19c057e64ece1b4ac986ab0f2f4d52d5a/matplotlib-3.10.7-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c17398b709a6cce3d9fdb1595c33e356d91c098cd9486cb2cc21ea2ea418e715", size = 9533949, upload-time = "2025-10-09T00:27:26.704Z" }, - { url = "https://files.pythonhosted.org/packages/de/ff/f3781b5057fa3786623ad8976fc9f7b0d02b2f28534751fd5a44240de4cf/matplotlib-3.10.7-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7146d64f561498764561e9cd0ed64fcf582e570fc519e6f521e2d0cfd43365e1", size = 9804247, upload-time = "2025-10-09T00:27:28.514Z" }, - { url = "https://files.pythonhosted.org/packages/47/5a/993a59facb8444efb0e197bf55f545ee449902dcee86a4dfc580c3b61314/matplotlib-3.10.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:90ad854c0a435da3104c01e2c6f0028d7e719b690998a2333d7218db80950722", size = 9595497, upload-time = "2025-10-09T00:27:30.418Z" }, - { url = "https://files.pythonhosted.org/packages/0d/a5/77c95aaa9bb32c345cbb49626ad8eb15550cba2e6d4c88081a6c2ac7b08d/matplotlib-3.10.7-cp314-cp314-win_amd64.whl", hash = "sha256:4645fc5d9d20ffa3a39361fcdbcec731382763b623b72627806bf251b6388866", size = 8252732, upload-time = "2025-10-09T00:27:32.332Z" }, - { url = "https://files.pythonhosted.org/packages/74/04/45d269b4268d222390d7817dae77b159651909669a34ee9fdee336db5883/matplotlib-3.10.7-cp314-cp314-win_arm64.whl", hash = "sha256:9257be2f2a03415f9105c486d304a321168e61ad450f6153d77c69504ad764bb", size = 8124240, upload-time = "2025-10-09T00:27:33.94Z" }, - { url = "https://files.pythonhosted.org/packages/4b/c7/ca01c607bb827158b439208c153d6f14ddb9fb640768f06f7ca3488ae67b/matplotlib-3.10.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1e4bbad66c177a8fdfa53972e5ef8be72a5f27e6a607cec0d8579abd0f3102b1", size = 8316938, upload-time = "2025-10-09T00:27:35.534Z" }, - { url = "https://files.pythonhosted.org/packages/84/d2/5539e66e9f56d2fdec94bb8436f5e449683b4e199bcc897c44fbe3c99e28/matplotlib-3.10.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d8eb7194b084b12feb19142262165832fc6ee879b945491d1c3d4660748020c4", size = 8178245, upload-time = "2025-10-09T00:27:37.334Z" }, - { url = "https://files.pythonhosted.org/packages/77/b5/e6ca22901fd3e4fe433a82e583436dd872f6c966fca7e63cf806b40356f8/matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d41379b05528091f00e1728004f9a8d7191260f3862178b88e8fd770206318", size = 9541411, upload-time = "2025-10-09T00:27:39.387Z" }, - { url = "https://files.pythonhosted.org/packages/9e/99/a4524db57cad8fee54b7237239a8f8360bfcfa3170d37c9e71c090c0f409/matplotlib-3.10.7-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a74f79fafb2e177f240579bc83f0b60f82cc47d2f1d260f422a0627207008ca", size = 9803664, upload-time = "2025-10-09T00:27:41.492Z" }, - { url = "https://files.pythonhosted.org/packages/e6/a5/85e2edf76ea0ad4288d174926d9454ea85f3ce5390cc4e6fab196cbf250b/matplotlib-3.10.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:702590829c30aada1e8cef0568ddbffa77ca747b4d6e36c6d173f66e301f89cc", size = 9594066, upload-time = "2025-10-09T00:27:43.694Z" }, - { url = "https://files.pythonhosted.org/packages/39/69/9684368a314f6d83fe5c5ad2a4121a3a8e03723d2e5c8ea17b66c1bad0e7/matplotlib-3.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:f79d5de970fc90cd5591f60053aecfce1fcd736e0303d9f0bf86be649fa68fb8", size = 8342832, upload-time = "2025-10-09T00:27:45.543Z" }, - { url = "https://files.pythonhosted.org/packages/04/5f/e22e08da14bc1a0894184640d47819d2338b792732e20d292bf86e5ab785/matplotlib-3.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:cb783436e47fcf82064baca52ce748af71725d0352e1d31564cbe9c95df92b9c", size = 8172585, upload-time = "2025-10-09T00:27:47.185Z" }, -] - -[[package]] -name = "maxsmooth" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "cvxopt" }, - { name = "cvxpy" }, - { name = "jax" }, - { name = "jaxopt" }, - { name = "matplotlib" }, - { name = "numpy" }, - { name = "progressbar" }, - { name = "scipy" }, -] - -[package.metadata] -requires-dist = [ - { name = "cvxopt", specifier = ">=1.3.2" }, - { name = "cvxpy", specifier = ">=1.7.3" }, - { name = "jax", specifier = ">=0.8.0" }, - { name = "jaxopt", specifier = ">=0.8.5" }, - { name = "matplotlib", specifier = ">=3.10.7" }, - { name = "numpy", specifier = ">=2.3.4" }, - { name = "progressbar", specifier = ">=2.5" }, - { name = "scipy", specifier = ">=1.16.3" }, -] - -[[package]] -name = "ml-dtypes" -version = "0.5.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/78/a7/aad060393123cfb383956dca68402aff3db1e1caffd5764887ed5153f41b/ml_dtypes-0.5.3.tar.gz", hash = "sha256:95ce33057ba4d05df50b1f3cfefab22e351868a843b3b15a46c65836283670c9", size = 692316, upload-time = "2025-07-29T18:39:19.454Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/87/1bcc98a66de7b2455dfb292f271452cac9edc4e870796e0d87033524d790/ml_dtypes-0.5.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5103856a225465371fe119f2fef737402b705b810bd95ad5f348e6e1a6ae21af", size = 663781, upload-time = "2025-07-29T18:38:42.984Z" }, - { url = "https://files.pythonhosted.org/packages/fd/2c/bd2a79ba7c759ee192b5601b675b180a3fd6ccf48ffa27fe1782d280f1a7/ml_dtypes-0.5.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cae435a68861660af81fa3c5af16b70ca11a17275c5b662d9c6f58294e0f113", size = 4956217, upload-time = "2025-07-29T18:38:44.65Z" }, - { url = "https://files.pythonhosted.org/packages/14/f3/091ba84e5395d7fe5b30c081a44dec881cd84b408db1763ee50768b2ab63/ml_dtypes-0.5.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6936283b56d74fbec431ca57ce58a90a908fdbd14d4e2d22eea6d72bb208a7b7", size = 4933109, upload-time = "2025-07-29T18:38:46.405Z" }, - { url = "https://files.pythonhosted.org/packages/bc/24/054036dbe32c43295382c90a1363241684c4d6aaa1ecc3df26bd0c8d5053/ml_dtypes-0.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:d0f730a17cf4f343b2c7ad50cee3bd19e969e793d2be6ed911f43086460096e4", size = 208187, upload-time = "2025-07-29T18:38:48.24Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3d/7dc3ec6794a4a9004c765e0c341e32355840b698f73fd2daff46f128afc1/ml_dtypes-0.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:2db74788fc01914a3c7f7da0763427280adfc9cd377e9604b6b64eb8097284bd", size = 161559, upload-time = "2025-07-29T18:38:50.493Z" }, - { url = "https://files.pythonhosted.org/packages/12/91/e6c7a0d67a152b9330445f9f0cf8ae6eee9b83f990b8c57fe74631e42a90/ml_dtypes-0.5.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:93c36a08a6d158db44f2eb9ce3258e53f24a9a4a695325a689494f0fdbc71770", size = 689321, upload-time = "2025-07-29T18:38:52.03Z" }, - { url = "https://files.pythonhosted.org/packages/9e/6c/b7b94b84a104a5be1883305b87d4c6bd6ae781504474b4cca067cb2340ec/ml_dtypes-0.5.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0e44a3761f64bc009d71ddb6d6c71008ba21b53ab6ee588dadab65e2fa79eafc", size = 5274495, upload-time = "2025-07-29T18:38:53.797Z" }, - { url = "https://files.pythonhosted.org/packages/5b/38/6266604dffb43378055394ea110570cf261a49876fc48f548dfe876f34cc/ml_dtypes-0.5.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdf40d2aaabd3913dec11840f0d0ebb1b93134f99af6a0a4fd88ffe924928ab4", size = 5285422, upload-time = "2025-07-29T18:38:56.603Z" }, - { url = "https://files.pythonhosted.org/packages/7c/88/8612ff177d043a474b9408f0382605d881eeb4125ba89d4d4b3286573a83/ml_dtypes-0.5.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:aec640bd94c4c85c0d11e2733bd13cbb10438fb004852996ec0efbc6cacdaf70", size = 661182, upload-time = "2025-07-29T18:38:58.414Z" }, - { url = "https://files.pythonhosted.org/packages/6f/2b/0569a5e88b29240d373e835107c94ae9256fb2191d3156b43b2601859eff/ml_dtypes-0.5.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bda32ce212baa724e03c68771e5c69f39e584ea426bfe1a701cb01508ffc7035", size = 4956187, upload-time = "2025-07-29T18:39:00.611Z" }, - { url = "https://files.pythonhosted.org/packages/51/66/273c2a06ae44562b104b61e6b14444da00061fd87652506579d7eb2c40b1/ml_dtypes-0.5.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c205cac07d24a29840c163d6469f61069ce4b065518519216297fc2f261f8db9", size = 4930911, upload-time = "2025-07-29T18:39:02.405Z" }, - { url = "https://files.pythonhosted.org/packages/93/ab/606be3e87dc0821bd360c8c1ee46108025c31a4f96942b63907bb441b87d/ml_dtypes-0.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:cd7c0bb22d4ff86d65ad61b5dd246812e8993fbc95b558553624c33e8b6903ea", size = 216664, upload-time = "2025-07-29T18:39:03.927Z" }, - { url = "https://files.pythonhosted.org/packages/30/a2/e900690ca47d01dffffd66375c5de8c4f8ced0f1ef809ccd3b25b3e6b8fa/ml_dtypes-0.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:9d55ea7f7baf2aed61bf1872116cefc9d0c3693b45cae3916897ee27ef4b835e", size = 160203, upload-time = "2025-07-29T18:39:05.671Z" }, - { url = "https://files.pythonhosted.org/packages/53/21/783dfb51f40d2660afeb9bccf3612b99f6a803d980d2a09132b0f9d216ab/ml_dtypes-0.5.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:e12e29764a0e66a7a31e9b8bf1de5cc0423ea72979f45909acd4292de834ccd3", size = 689324, upload-time = "2025-07-29T18:39:07.567Z" }, - { url = "https://files.pythonhosted.org/packages/09/f7/a82d249c711abf411ac027b7163f285487f5e615c3e0716c61033ce996ab/ml_dtypes-0.5.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19f6c3a4f635c2fc9e2aa7d91416bd7a3d649b48350c51f7f715a09370a90d93", size = 5275917, upload-time = "2025-07-29T18:39:09.339Z" }, - { url = "https://files.pythonhosted.org/packages/7f/3c/541c4b30815ab90ebfbb51df15d0b4254f2f9f1e2b4907ab229300d5e6f2/ml_dtypes-0.5.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ab039ffb40f3dc0aeeeba84fd6c3452781b5e15bef72e2d10bcb33e4bbffc39", size = 5285284, upload-time = "2025-07-29T18:39:11.532Z" }, -] - -[[package]] -name = "numpy" -version = "2.3.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/f4/098d2270d52b41f1bd7db9fc288aaa0400cb48c2a3e2af6fa365d9720947/numpy-2.3.4.tar.gz", hash = "sha256:a7d018bfedb375a8d979ac758b120ba846a7fe764911a64465fd87b8729f4a6a", size = 20582187, upload-time = "2025-10-15T16:18:11.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/57/7e/b72610cc91edf138bc588df5150957a4937221ca6058b825b4725c27be62/numpy-2.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c090d4860032b857d94144d1a9976b8e36709e40386db289aaf6672de2a81966", size = 20950335, upload-time = "2025-10-15T16:16:10.304Z" }, - { url = "https://files.pythonhosted.org/packages/3e/46/bdd3370dcea2f95ef14af79dbf81e6927102ddf1cc54adc0024d61252fd9/numpy-2.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a13fc473b6db0be619e45f11f9e81260f7302f8d180c49a22b6e6120022596b3", size = 14179878, upload-time = "2025-10-15T16:16:12.595Z" }, - { url = "https://files.pythonhosted.org/packages/ac/01/5a67cb785bda60f45415d09c2bc245433f1c68dd82eef9c9002c508b5a65/numpy-2.3.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:3634093d0b428e6c32c3a69b78e554f0cd20ee420dcad5a9f3b2a63762ce4197", size = 5108673, upload-time = "2025-10-15T16:16:14.877Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cd/8428e23a9fcebd33988f4cb61208fda832800ca03781f471f3727a820704/numpy-2.3.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:043885b4f7e6e232d7df4f51ffdef8c36320ee9d5f227b380ea636722c7ed12e", size = 6641438, upload-time = "2025-10-15T16:16:16.805Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d1/913fe563820f3c6b079f992458f7331278dcd7ba8427e8e745af37ddb44f/numpy-2.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4ee6a571d1e4f0ea6d5f22d6e5fbd6ed1dc2b18542848e1e7301bd190500c9d7", size = 14281290, upload-time = "2025-10-15T16:16:18.764Z" }, - { url = "https://files.pythonhosted.org/packages/9e/7e/7d306ff7cb143e6d975cfa7eb98a93e73495c4deabb7d1b5ecf09ea0fd69/numpy-2.3.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc8a63918b04b8571789688b2780ab2b4a33ab44bfe8ccea36d3eba51228c953", size = 16636543, upload-time = "2025-10-15T16:16:21.072Z" }, - { url = "https://files.pythonhosted.org/packages/47/6a/8cfc486237e56ccfb0db234945552a557ca266f022d281a2f577b98e955c/numpy-2.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:40cc556d5abbc54aabe2b1ae287042d7bdb80c08edede19f0c0afb36ae586f37", size = 16056117, upload-time = "2025-10-15T16:16:23.369Z" }, - { url = "https://files.pythonhosted.org/packages/b1/0e/42cb5e69ea901e06ce24bfcc4b5664a56f950a70efdcf221f30d9615f3f3/numpy-2.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ecb63014bb7f4ce653f8be7f1df8cbc6093a5a2811211770f6606cc92b5a78fd", size = 18577788, upload-time = "2025-10-15T16:16:27.496Z" }, - { url = "https://files.pythonhosted.org/packages/86/92/41c3d5157d3177559ef0a35da50f0cda7fa071f4ba2306dd36818591a5bc/numpy-2.3.4-cp313-cp313-win32.whl", hash = "sha256:e8370eb6925bb8c1c4264fec52b0384b44f675f191df91cbe0140ec9f0955646", size = 6282620, upload-time = "2025-10-15T16:16:29.811Z" }, - { url = "https://files.pythonhosted.org/packages/09/97/fd421e8bc50766665ad35536c2bb4ef916533ba1fdd053a62d96cc7c8b95/numpy-2.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:56209416e81a7893036eea03abcb91c130643eb14233b2515c90dcac963fe99d", size = 12784672, upload-time = "2025-10-15T16:16:31.589Z" }, - { url = "https://files.pythonhosted.org/packages/ad/df/5474fb2f74970ca8eb978093969b125a84cc3d30e47f82191f981f13a8a0/numpy-2.3.4-cp313-cp313-win_arm64.whl", hash = "sha256:a700a4031bc0fd6936e78a752eefb79092cecad2599ea9c8039c548bc097f9bc", size = 10196702, upload-time = "2025-10-15T16:16:33.902Z" }, - { url = "https://files.pythonhosted.org/packages/11/83/66ac031464ec1767ea3ed48ce40f615eb441072945e98693bec0bcd056cc/numpy-2.3.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:86966db35c4040fdca64f0816a1c1dd8dbd027d90fca5a57e00e1ca4cd41b879", size = 21049003, upload-time = "2025-10-15T16:16:36.101Z" }, - { url = "https://files.pythonhosted.org/packages/5f/99/5b14e0e686e61371659a1d5bebd04596b1d72227ce36eed121bb0aeab798/numpy-2.3.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:838f045478638b26c375ee96ea89464d38428c69170360b23a1a50fa4baa3562", size = 14302980, upload-time = "2025-10-15T16:16:39.124Z" }, - { url = "https://files.pythonhosted.org/packages/2c/44/e9486649cd087d9fc6920e3fc3ac2aba10838d10804b1e179fb7cbc4e634/numpy-2.3.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d7315ed1dab0286adca467377c8381cd748f3dc92235f22a7dfc42745644a96a", size = 5231472, upload-time = "2025-10-15T16:16:41.168Z" }, - { url = "https://files.pythonhosted.org/packages/3e/51/902b24fa8887e5fe2063fd61b1895a476d0bbf46811ab0c7fdf4bd127345/numpy-2.3.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:84f01a4d18b2cc4ade1814a08e5f3c907b079c847051d720fad15ce37aa930b6", size = 6739342, upload-time = "2025-10-15T16:16:43.777Z" }, - { url = "https://files.pythonhosted.org/packages/34/f1/4de9586d05b1962acdcdb1dc4af6646361a643f8c864cef7c852bf509740/numpy-2.3.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:817e719a868f0dacde4abdfc5c1910b301877970195db9ab6a5e2c4bd5b121f7", size = 14354338, upload-time = "2025-10-15T16:16:46.081Z" }, - { url = "https://files.pythonhosted.org/packages/1f/06/1c16103b425de7969d5a76bdf5ada0804b476fed05d5f9e17b777f1cbefd/numpy-2.3.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85e071da78d92a214212cacea81c6da557cab307f2c34b5f85b628e94803f9c0", size = 16702392, upload-time = "2025-10-15T16:16:48.455Z" }, - { url = "https://files.pythonhosted.org/packages/34/b2/65f4dc1b89b5322093572b6e55161bb42e3e0487067af73627f795cc9d47/numpy-2.3.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2ec646892819370cf3558f518797f16597b4e4669894a2ba712caccc9da53f1f", size = 16134998, upload-time = "2025-10-15T16:16:51.114Z" }, - { url = "https://files.pythonhosted.org/packages/d4/11/94ec578896cdb973aaf56425d6c7f2aff4186a5c00fac15ff2ec46998b46/numpy-2.3.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:035796aaaddfe2f9664b9a9372f089cfc88bd795a67bd1bfe15e6e770934cf64", size = 18651574, upload-time = "2025-10-15T16:16:53.429Z" }, - { url = "https://files.pythonhosted.org/packages/62/b7/7efa763ab33dbccf56dade36938a77345ce8e8192d6b39e470ca25ff3cd0/numpy-2.3.4-cp313-cp313t-win32.whl", hash = "sha256:fea80f4f4cf83b54c3a051f2f727870ee51e22f0248d3114b8e755d160b38cfb", size = 6413135, upload-time = "2025-10-15T16:16:55.992Z" }, - { url = "https://files.pythonhosted.org/packages/43/70/aba4c38e8400abcc2f345e13d972fb36c26409b3e644366db7649015f291/numpy-2.3.4-cp313-cp313t-win_amd64.whl", hash = "sha256:15eea9f306b98e0be91eb344a94c0e630689ef302e10c2ce5f7e11905c704f9c", size = 12928582, upload-time = "2025-10-15T16:16:57.943Z" }, - { url = "https://files.pythonhosted.org/packages/67/63/871fad5f0073fc00fbbdd7232962ea1ac40eeaae2bba66c76214f7954236/numpy-2.3.4-cp313-cp313t-win_arm64.whl", hash = "sha256:b6c231c9c2fadbae4011ca5e7e83e12dc4a5072f1a1d85a0a7b3ed754d145a40", size = 10266691, upload-time = "2025-10-15T16:17:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/72/71/ae6170143c115732470ae3a2d01512870dd16e0953f8a6dc89525696069b/numpy-2.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:81c3e6d8c97295a7360d367f9f8553973651b76907988bb6066376bc2252f24e", size = 20955580, upload-time = "2025-10-15T16:17:02.509Z" }, - { url = "https://files.pythonhosted.org/packages/af/39/4be9222ffd6ca8a30eda033d5f753276a9c3426c397bb137d8e19dedd200/numpy-2.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7c26b0b2bf58009ed1f38a641f3db4be8d960a417ca96d14e5b06df1506d41ff", size = 14188056, upload-time = "2025-10-15T16:17:04.873Z" }, - { url = "https://files.pythonhosted.org/packages/6c/3d/d85f6700d0a4aa4f9491030e1021c2b2b7421b2b38d01acd16734a2bfdc7/numpy-2.3.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:62b2198c438058a20b6704351b35a1d7db881812d8512d67a69c9de1f18ca05f", size = 5116555, upload-time = "2025-10-15T16:17:07.499Z" }, - { url = "https://files.pythonhosted.org/packages/bf/04/82c1467d86f47eee8a19a464c92f90a9bb68ccf14a54c5224d7031241ffb/numpy-2.3.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:9d729d60f8d53a7361707f4b68a9663c968882dd4f09e0d58c044c8bf5faee7b", size = 6643581, upload-time = "2025-10-15T16:17:09.774Z" }, - { url = "https://files.pythonhosted.org/packages/0c/d3/c79841741b837e293f48bd7db89d0ac7a4f2503b382b78a790ef1dc778a5/numpy-2.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd0c630cf256b0a7fd9d0a11c9413b42fef5101219ce6ed5a09624f5a65392c7", size = 14299186, upload-time = "2025-10-15T16:17:11.937Z" }, - { url = "https://files.pythonhosted.org/packages/e8/7e/4a14a769741fbf237eec5a12a2cbc7a4c4e061852b6533bcb9e9a796c908/numpy-2.3.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5e081bc082825f8b139f9e9fe42942cb4054524598aaeb177ff476cc76d09d2", size = 16638601, upload-time = "2025-10-15T16:17:14.391Z" }, - { url = "https://files.pythonhosted.org/packages/93/87/1c1de269f002ff0a41173fe01dcc925f4ecff59264cd8f96cf3b60d12c9b/numpy-2.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15fb27364ed84114438fff8aaf998c9e19adbeba08c0b75409f8c452a8692c52", size = 16074219, upload-time = "2025-10-15T16:17:17.058Z" }, - { url = "https://files.pythonhosted.org/packages/cd/28/18f72ee77408e40a76d691001ae599e712ca2a47ddd2c4f695b16c65f077/numpy-2.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:85d9fb2d8cd998c84d13a79a09cc0c1091648e848e4e6249b0ccd7f6b487fa26", size = 18576702, upload-time = "2025-10-15T16:17:19.379Z" }, - { url = "https://files.pythonhosted.org/packages/c3/76/95650169b465ececa8cf4b2e8f6df255d4bf662775e797ade2025cc51ae6/numpy-2.3.4-cp314-cp314-win32.whl", hash = "sha256:e73d63fd04e3a9d6bc187f5455d81abfad05660b212c8804bf3b407e984cd2bc", size = 6337136, upload-time = "2025-10-15T16:17:22.886Z" }, - { url = "https://files.pythonhosted.org/packages/dc/89/a231a5c43ede5d6f77ba4a91e915a87dea4aeea76560ba4d2bf185c683f0/numpy-2.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:3da3491cee49cf16157e70f607c03a217ea6647b1cea4819c4f48e53d49139b9", size = 12920542, upload-time = "2025-10-15T16:17:24.783Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0c/ae9434a888f717c5ed2ff2393b3f344f0ff6f1c793519fa0c540461dc530/numpy-2.3.4-cp314-cp314-win_arm64.whl", hash = "sha256:6d9cd732068e8288dbe2717177320723ccec4fb064123f0caf9bbd90ab5be868", size = 10480213, upload-time = "2025-10-15T16:17:26.935Z" }, - { url = "https://files.pythonhosted.org/packages/83/4b/c4a5f0841f92536f6b9592694a5b5f68c9ab37b775ff342649eadf9055d3/numpy-2.3.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:22758999b256b595cf0b1d102b133bb61866ba5ceecf15f759623b64c020c9ec", size = 21052280, upload-time = "2025-10-15T16:17:29.638Z" }, - { url = "https://files.pythonhosted.org/packages/3e/80/90308845fc93b984d2cc96d83e2324ce8ad1fd6efea81b324cba4b673854/numpy-2.3.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9cb177bc55b010b19798dc5497d540dea67fd13a8d9e882b2dae71de0cf09eb3", size = 14302930, upload-time = "2025-10-15T16:17:32.384Z" }, - { url = "https://files.pythonhosted.org/packages/3d/4e/07439f22f2a3b247cec4d63a713faae55e1141a36e77fb212881f7cda3fb/numpy-2.3.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0f2bcc76f1e05e5ab58893407c63d90b2029908fa41f9f1cc51eecce936c3365", size = 5231504, upload-time = "2025-10-15T16:17:34.515Z" }, - { url = "https://files.pythonhosted.org/packages/ab/de/1e11f2547e2fe3d00482b19721855348b94ada8359aef5d40dd57bfae9df/numpy-2.3.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dc20bde86802df2ed8397a08d793da0ad7a5fd4ea3ac85d757bf5dd4ad7c252", size = 6739405, upload-time = "2025-10-15T16:17:36.128Z" }, - { url = "https://files.pythonhosted.org/packages/3b/40/8cd57393a26cebe2e923005db5134a946c62fa56a1087dc7c478f3e30837/numpy-2.3.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e199c087e2aa71c8f9ce1cb7a8e10677dc12457e7cc1be4798632da37c3e86e", size = 14354866, upload-time = "2025-10-15T16:17:38.884Z" }, - { url = "https://files.pythonhosted.org/packages/93/39/5b3510f023f96874ee6fea2e40dfa99313a00bf3ab779f3c92978f34aace/numpy-2.3.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85597b2d25ddf655495e2363fe044b0ae999b75bc4d630dc0d886484b03a5eb0", size = 16703296, upload-time = "2025-10-15T16:17:41.564Z" }, - { url = "https://files.pythonhosted.org/packages/41/0d/19bb163617c8045209c1996c4e427bccbc4bbff1e2c711f39203c8ddbb4a/numpy-2.3.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:04a69abe45b49c5955923cf2c407843d1c85013b424ae8a560bba16c92fe44a0", size = 16136046, upload-time = "2025-10-15T16:17:43.901Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c1/6dba12fdf68b02a21ac411c9df19afa66bed2540f467150ca64d246b463d/numpy-2.3.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e1708fac43ef8b419c975926ce1eaf793b0c13b7356cfab6ab0dc34c0a02ac0f", size = 18652691, upload-time = "2025-10-15T16:17:46.247Z" }, - { url = "https://files.pythonhosted.org/packages/f8/73/f85056701dbbbb910c51d846c58d29fd46b30eecd2b6ba760fc8b8a1641b/numpy-2.3.4-cp314-cp314t-win32.whl", hash = "sha256:863e3b5f4d9915aaf1b8ec79ae560ad21f0b8d5e3adc31e73126491bb86dee1d", size = 6485782, upload-time = "2025-10-15T16:17:48.872Z" }, - { url = "https://files.pythonhosted.org/packages/17/90/28fa6f9865181cb817c2471ee65678afa8a7e2a1fb16141473d5fa6bacc3/numpy-2.3.4-cp314-cp314t-win_amd64.whl", hash = "sha256:962064de37b9aef801d33bc579690f8bfe6c5e70e29b61783f60bcba838a14d6", size = 13113301, upload-time = "2025-10-15T16:17:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/54/23/08c002201a8e7e1f9afba93b97deceb813252d9cfd0d3351caed123dcf97/numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29", size = 10547532, upload-time = "2025-10-15T16:17:53.48Z" }, -] - -[[package]] -name = "opt-einsum" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004, upload-time = "2024-09-26T14:33:24.483Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932, upload-time = "2024-09-26T14:33:23.039Z" }, -] - -[[package]] -name = "osqp" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "joblib" }, - { name = "numpy" }, - { name = "scipy" }, - { name = "setuptools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/85/cf/023078d9985526494901e9ca91c59d17b2d2e5f87a047f4b8b9749ce5922/osqp-1.0.5.tar.gz", hash = "sha256:60b484cf829c99d94bb7ae4e9beb2e0895d94c5e64e074b5b27b6ef887941936", size = 56757, upload-time = "2025-10-15T14:05:33.613Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/13/bd94ec700462989623891078cfe911a1331e83054575acc8b5f78dcd3e46/osqp-1.0.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:da8e109d679d1faf2ed1142cd0bacd70fab5c91a7109bd85a6b228d423124dcb", size = 328512, upload-time = "2025-10-15T14:05:16.482Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e5/b7402123c33ee690b39cfcf35ac4bc77c5f0e5506b33112073063cb1c02c/osqp-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b99d308b2a6be07fd02a3712f4885feff31114b3eff35e1e97bc0caba61032e7", size = 302175, upload-time = "2025-10-15T14:05:17.688Z" }, - { url = "https://files.pythonhosted.org/packages/3c/3d/ad5aaa20780fbdc3bb240f1688a015d9cf07bd955b74f3443147cea82ecb/osqp-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3e8de72c880ccabaefcbc8418378426d4ea2e6dc6fd3acbd96de00a605f94ad", size = 335030, upload-time = "2025-10-15T14:05:18.92Z" }, - { url = "https://files.pythonhosted.org/packages/c0/56/56b7039c43457cfa113842f8345bd346af03caf2af403e0a91d040abacdc/osqp-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f8910df4c2e419078961cd4e7a4d6e14ed0269f66a0f2f774a895fc14ef8ff", size = 357417, upload-time = "2025-10-15T14:05:20.022Z" }, - { url = "https://files.pythonhosted.org/packages/f2/df/46ca217567451b12acc7585be2ee43089846792ae0340ce93ab7e662b47a/osqp-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:0a90b8fee99daa00760bd336dd074731289690700d9e7eae3900db233f8bfa02", size = 310518, upload-time = "2025-10-15T14:05:21.029Z" }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] - -[[package]] -name = "pillow" -version = "12.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493, upload-time = "2025-10-15T18:22:25.758Z" }, - { url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461, upload-time = "2025-10-15T18:22:27.286Z" }, - { url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912, upload-time = "2025-10-15T18:22:28.751Z" }, - { url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132, upload-time = "2025-10-15T18:22:30.641Z" }, - { url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099, upload-time = "2025-10-15T18:22:32.73Z" }, - { url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808, upload-time = "2025-10-15T18:22:34.337Z" }, - { url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804, upload-time = "2025-10-15T18:22:36.402Z" }, - { url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553, upload-time = "2025-10-15T18:22:38.066Z" }, - { url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729, upload-time = "2025-10-15T18:22:39.769Z" }, - { url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789, upload-time = "2025-10-15T18:22:41.437Z" }, - { url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917, upload-time = "2025-10-15T18:22:43.152Z" }, - { url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391, upload-time = "2025-10-15T18:22:44.753Z" }, - { url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477, upload-time = "2025-10-15T18:22:46.838Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918, upload-time = "2025-10-15T18:22:48.399Z" }, - { url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406, upload-time = "2025-10-15T18:22:49.905Z" }, - { url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218, upload-time = "2025-10-15T18:22:51.587Z" }, - { url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564, upload-time = "2025-10-15T18:22:53.215Z" }, - { url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260, upload-time = "2025-10-15T18:22:54.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248, upload-time = "2025-10-15T18:22:56.605Z" }, - { url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043, upload-time = "2025-10-15T18:22:58.53Z" }, - { url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915, upload-time = "2025-10-15T18:23:00.582Z" }, - { url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998, upload-time = "2025-10-15T18:23:02.627Z" }, - { url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201, upload-time = "2025-10-15T18:23:04.709Z" }, - { url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165, upload-time = "2025-10-15T18:23:06.46Z" }, - { url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834, upload-time = "2025-10-15T18:23:08.194Z" }, - { url = "https://files.pythonhosted.org/packages/54/2a/9a8c6ba2c2c07b71bec92cf63e03370ca5e5f5c5b119b742bcc0cde3f9c5/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9", size = 4045531, upload-time = "2025-10-15T18:23:10.121Z" }, - { url = "https://files.pythonhosted.org/packages/84/54/836fdbf1bfb3d66a59f0189ff0b9f5f666cee09c6188309300df04ad71fa/pillow-12.0.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2", size = 4120554, upload-time = "2025-10-15T18:23:12.14Z" }, - { url = "https://files.pythonhosted.org/packages/0d/cd/16aec9f0da4793e98e6b54778a5fbce4f375c6646fe662e80600b8797379/pillow-12.0.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a", size = 3576812, upload-time = "2025-10-15T18:23:13.962Z" }, - { url = "https://files.pythonhosted.org/packages/f6/b7/13957fda356dc46339298b351cae0d327704986337c3c69bb54628c88155/pillow-12.0.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b", size = 5252689, upload-time = "2025-10-15T18:23:15.562Z" }, - { url = "https://files.pythonhosted.org/packages/fc/f5/eae31a306341d8f331f43edb2e9122c7661b975433de5e447939ae61c5da/pillow-12.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad", size = 4650186, upload-time = "2025-10-15T18:23:17.379Z" }, - { url = "https://files.pythonhosted.org/packages/86/62/2a88339aa40c4c77e79108facbd307d6091e2c0eb5b8d3cf4977cfca2fe6/pillow-12.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01", size = 6230308, upload-time = "2025-10-15T18:23:18.971Z" }, - { url = "https://files.pythonhosted.org/packages/c7/33/5425a8992bcb32d1cb9fa3dd39a89e613d09a22f2c8083b7bf43c455f760/pillow-12.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c", size = 8039222, upload-time = "2025-10-15T18:23:20.909Z" }, - { url = "https://files.pythonhosted.org/packages/d8/61/3f5d3b35c5728f37953d3eec5b5f3e77111949523bd2dd7f31a851e50690/pillow-12.0.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e", size = 6346657, upload-time = "2025-10-15T18:23:23.077Z" }, - { url = "https://files.pythonhosted.org/packages/3a/be/ee90a3d79271227e0f0a33c453531efd6ed14b2e708596ba5dd9be948da3/pillow-12.0.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e", size = 7038482, upload-time = "2025-10-15T18:23:25.005Z" }, - { url = "https://files.pythonhosted.org/packages/44/34/a16b6a4d1ad727de390e9bd9f19f5f669e079e5826ec0f329010ddea492f/pillow-12.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9", size = 6461416, upload-time = "2025-10-15T18:23:27.009Z" }, - { url = "https://files.pythonhosted.org/packages/b6/39/1aa5850d2ade7d7ba9f54e4e4c17077244ff7a2d9e25998c38a29749eb3f/pillow-12.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab", size = 7131584, upload-time = "2025-10-15T18:23:29.752Z" }, - { url = "https://files.pythonhosted.org/packages/bf/db/4fae862f8fad0167073a7733973bfa955f47e2cac3dc3e3e6257d10fab4a/pillow-12.0.0-cp314-cp314-win32.whl", hash = "sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b", size = 6400621, upload-time = "2025-10-15T18:23:32.06Z" }, - { url = "https://files.pythonhosted.org/packages/2b/24/b350c31543fb0107ab2599464d7e28e6f856027aadda995022e695313d94/pillow-12.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b", size = 7142916, upload-time = "2025-10-15T18:23:34.71Z" }, - { url = "https://files.pythonhosted.org/packages/0f/9b/0ba5a6fd9351793996ef7487c4fdbde8d3f5f75dbedc093bb598648fddf0/pillow-12.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0", size = 2523836, upload-time = "2025-10-15T18:23:36.967Z" }, - { url = "https://files.pythonhosted.org/packages/f5/7a/ceee0840aebc579af529b523d530840338ecf63992395842e54edc805987/pillow-12.0.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6", size = 5255092, upload-time = "2025-10-15T18:23:38.573Z" }, - { url = "https://files.pythonhosted.org/packages/44/76/20776057b4bfd1aef4eeca992ebde0f53a4dce874f3ae693d0ec90a4f79b/pillow-12.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6", size = 4653158, upload-time = "2025-10-15T18:23:40.238Z" }, - { url = "https://files.pythonhosted.org/packages/82/3f/d9ff92ace07be8836b4e7e87e6a4c7a8318d47c2f1463ffcf121fc57d9cb/pillow-12.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1", size = 6267882, upload-time = "2025-10-15T18:23:42.434Z" }, - { url = "https://files.pythonhosted.org/packages/9f/7a/4f7ff87f00d3ad33ba21af78bfcd2f032107710baf8280e3722ceec28cda/pillow-12.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e", size = 8071001, upload-time = "2025-10-15T18:23:44.29Z" }, - { url = "https://files.pythonhosted.org/packages/75/87/fcea108944a52dad8cca0715ae6247e271eb80459364a98518f1e4f480c1/pillow-12.0.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca", size = 6380146, upload-time = "2025-10-15T18:23:46.065Z" }, - { url = "https://files.pythonhosted.org/packages/91/52/0d31b5e571ef5fd111d2978b84603fce26aba1b6092f28e941cb46570745/pillow-12.0.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925", size = 7067344, upload-time = "2025-10-15T18:23:47.898Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f4/2dd3d721f875f928d48e83bb30a434dee75a2531bca839bb996bb0aa5a91/pillow-12.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8", size = 6491864, upload-time = "2025-10-15T18:23:49.607Z" }, - { url = "https://files.pythonhosted.org/packages/30/4b/667dfcf3d61fc309ba5a15b141845cece5915e39b99c1ceab0f34bf1d124/pillow-12.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4", size = 7158911, upload-time = "2025-10-15T18:23:51.351Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2f/16cabcc6426c32218ace36bf0d55955e813f2958afddbf1d391849fee9d1/pillow-12.0.0-cp314-cp314t-win32.whl", hash = "sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52", size = 6408045, upload-time = "2025-10-15T18:23:53.177Z" }, - { url = "https://files.pythonhosted.org/packages/35/73/e29aa0c9c666cf787628d3f0dcf379f4791fba79f4936d02f8b37165bdf8/pillow-12.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a", size = 7148282, upload-time = "2025-10-15T18:23:55.316Z" }, - { url = "https://files.pythonhosted.org/packages/c1/70/6b41bdcddf541b437bbb9f47f94d2db5d9ddef6c37ccab8c9107743748a4/pillow-12.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7", size = 2525630, upload-time = "2025-10-15T18:23:57.149Z" }, -] - -[[package]] -name = "progressbar" -version = "2.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/a6/b8e451f6cff1c99b4747a2f7235aa904d2d49e8e1464e0b798272aa84358/progressbar-2.5.tar.gz", hash = "sha256:5d81cb529da2e223b53962afd6c8ca0f05c6670e40309a7219eacc36af9b6c63", size = 10046, upload-time = "2018-06-29T02:32:00.222Z" } - -[[package]] -name = "pycparser" -version = "2.23" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, -] - -[[package]] -name = "pyparsing" -version = "3.2.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274, upload-time = "2025-09-21T04:11:06.277Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890, upload-time = "2025-09-21T04:11:04.117Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "scipy" -version = "1.16.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/f1/57e8327ab1508272029e27eeef34f2302ffc156b69e7e233e906c2a5c379/scipy-1.16.3-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:d2ec56337675e61b312179a1ad124f5f570c00f920cc75e1000025451b88241c", size = 36617856, upload-time = "2025-10-28T17:33:31.375Z" }, - { url = "https://files.pythonhosted.org/packages/44/13/7e63cfba8a7452eb756306aa2fd9b37a29a323b672b964b4fdeded9a3f21/scipy-1.16.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:16b8bc35a4cc24db80a0ec836a9286d0e31b2503cb2fd7ff7fb0e0374a97081d", size = 28874306, upload-time = "2025-10-28T17:33:36.516Z" }, - { url = "https://files.pythonhosted.org/packages/15/65/3a9400efd0228a176e6ec3454b1fa998fbbb5a8defa1672c3f65706987db/scipy-1.16.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:5803c5fadd29de0cf27fa08ccbfe7a9e5d741bf63e4ab1085437266f12460ff9", size = 20865371, upload-time = "2025-10-28T17:33:42.094Z" }, - { url = "https://files.pythonhosted.org/packages/33/d7/eda09adf009a9fb81827194d4dd02d2e4bc752cef16737cc4ef065234031/scipy-1.16.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:b81c27fc41954319a943d43b20e07c40bdcd3ff7cf013f4fb86286faefe546c4", size = 23524877, upload-time = "2025-10-28T17:33:48.483Z" }, - { url = "https://files.pythonhosted.org/packages/7d/6b/3f911e1ebc364cb81320223a3422aab7d26c9c7973109a9cd0f27c64c6c0/scipy-1.16.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0c3b4dd3d9b08dbce0f3440032c52e9e2ab9f96ade2d3943313dfe51a7056959", size = 33342103, upload-time = "2025-10-28T17:33:56.495Z" }, - { url = "https://files.pythonhosted.org/packages/21/f6/4bfb5695d8941e5c570a04d9fcd0d36bce7511b7d78e6e75c8f9791f82d0/scipy-1.16.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7dc1360c06535ea6116a2220f760ae572db9f661aba2d88074fe30ec2aa1ff88", size = 35697297, upload-time = "2025-10-28T17:34:04.722Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6496dadbc80d8d896ff72511ecfe2316b50313bfc3ebf07a3f580f08bd8c/scipy-1.16.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:663b8d66a8748051c3ee9c96465fb417509315b99c71550fda2591d7dd634234", size = 36021756, upload-time = "2025-10-28T17:34:13.482Z" }, - { url = "https://files.pythonhosted.org/packages/fe/bd/a8c7799e0136b987bda3e1b23d155bcb31aec68a4a472554df5f0937eef7/scipy-1.16.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eab43fae33a0c39006a88096cd7b4f4ef545ea0447d250d5ac18202d40b6611d", size = 38696566, upload-time = "2025-10-28T17:34:22.384Z" }, - { url = "https://files.pythonhosted.org/packages/cd/01/1204382461fcbfeb05b6161b594f4007e78b6eba9b375382f79153172b4d/scipy-1.16.3-cp313-cp313-win_amd64.whl", hash = "sha256:062246acacbe9f8210de8e751b16fc37458213f124bef161a5a02c7a39284304", size = 38529877, upload-time = "2025-10-28T17:35:51.076Z" }, - { url = "https://files.pythonhosted.org/packages/7f/14/9d9fbcaa1260a94f4bb5b64ba9213ceb5d03cd88841fe9fd1ffd47a45b73/scipy-1.16.3-cp313-cp313-win_arm64.whl", hash = "sha256:50a3dbf286dbc7d84f176f9a1574c705f277cb6565069f88f60db9eafdbe3ee2", size = 25455366, upload-time = "2025-10-28T17:35:59.014Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a3/9ec205bd49f42d45d77f1730dbad9ccf146244c1647605cf834b3a8c4f36/scipy-1.16.3-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:fb4b29f4cf8cc5a8d628bc8d8e26d12d7278cd1f219f22698a378c3d67db5e4b", size = 37027931, upload-time = "2025-10-28T17:34:31.451Z" }, - { url = "https://files.pythonhosted.org/packages/25/06/ca9fd1f3a4589cbd825b1447e5db3a8ebb969c1eaf22c8579bd286f51b6d/scipy-1.16.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:8d09d72dc92742988b0e7750bddb8060b0c7079606c0d24a8cc8e9c9c11f9079", size = 29400081, upload-time = "2025-10-28T17:34:39.087Z" }, - { url = "https://files.pythonhosted.org/packages/6a/56/933e68210d92657d93fb0e381683bc0e53a965048d7358ff5fbf9e6a1b17/scipy-1.16.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:03192a35e661470197556de24e7cb1330d84b35b94ead65c46ad6f16f6b28f2a", size = 21391244, upload-time = "2025-10-28T17:34:45.234Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7e/779845db03dc1418e215726329674b40576879b91814568757ff0014ad65/scipy-1.16.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:57d01cb6f85e34f0946b33caa66e892aae072b64b034183f3d87c4025802a119", size = 23929753, upload-time = "2025-10-28T17:34:51.793Z" }, - { url = "https://files.pythonhosted.org/packages/4c/4b/f756cf8161d5365dcdef9e5f460ab226c068211030a175d2fc7f3f41ca64/scipy-1.16.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:96491a6a54e995f00a28a3c3badfff58fd093bf26cd5fb34a2188c8c756a3a2c", size = 33496912, upload-time = "2025-10-28T17:34:59.8Z" }, - { url = "https://files.pythonhosted.org/packages/09/b5/222b1e49a58668f23839ca1542a6322bb095ab8d6590d4f71723869a6c2c/scipy-1.16.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cd13e354df9938598af2be05822c323e97132d5e6306b83a3b4ee6724c6e522e", size = 35802371, upload-time = "2025-10-28T17:35:08.173Z" }, - { url = "https://files.pythonhosted.org/packages/c1/8d/5964ef68bb31829bde27611f8c9deeac13764589fe74a75390242b64ca44/scipy-1.16.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63d3cdacb8a824a295191a723ee5e4ea7768ca5ca5f2838532d9f2e2b3ce2135", size = 36190477, upload-time = "2025-10-28T17:35:16.7Z" }, - { url = "https://files.pythonhosted.org/packages/ab/f2/b31d75cb9b5fa4dd39a0a931ee9b33e7f6f36f23be5ef560bf72e0f92f32/scipy-1.16.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e7efa2681ea410b10dde31a52b18b0154d66f2485328830e45fdf183af5aefc6", size = 38796678, upload-time = "2025-10-28T17:35:26.354Z" }, - { url = "https://files.pythonhosted.org/packages/b4/1e/b3723d8ff64ab548c38d87055483714fefe6ee20e0189b62352b5e015bb1/scipy-1.16.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2d1ae2cf0c350e7705168ff2429962a89ad90c2d49d1dd300686d8b2a5af22fc", size = 38640178, upload-time = "2025-10-28T17:35:35.304Z" }, - { url = "https://files.pythonhosted.org/packages/8e/f3/d854ff38789aca9b0cc23008d607ced9de4f7ab14fa1ca4329f86b3758ca/scipy-1.16.3-cp313-cp313t-win_arm64.whl", hash = "sha256:0c623a54f7b79dd88ef56da19bc2873afec9673a48f3b85b18e4d402bdd29a5a", size = 25803246, upload-time = "2025-10-28T17:35:42.155Z" }, - { url = "https://files.pythonhosted.org/packages/99/f6/99b10fd70f2d864c1e29a28bbcaa0c6340f9d8518396542d9ea3b4aaae15/scipy-1.16.3-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:875555ce62743e1d54f06cdf22c1e0bc47b91130ac40fe5d783b6dfa114beeb6", size = 36606469, upload-time = "2025-10-28T17:36:08.741Z" }, - { url = "https://files.pythonhosted.org/packages/4d/74/043b54f2319f48ea940dd025779fa28ee360e6b95acb7cd188fad4391c6b/scipy-1.16.3-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:bb61878c18a470021fb515a843dc7a76961a8daceaaaa8bad1332f1bf4b54657", size = 28872043, upload-time = "2025-10-28T17:36:16.599Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e1/24b7e50cc1c4ee6ffbcb1f27fe9f4c8b40e7911675f6d2d20955f41c6348/scipy-1.16.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:f2622206f5559784fa5c4b53a950c3c7c1cf3e84ca1b9c4b6c03f062f289ca26", size = 20862952, upload-time = "2025-10-28T17:36:22.966Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3a/3e8c01a4d742b730df368e063787c6808597ccb38636ed821d10b39ca51b/scipy-1.16.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7f68154688c515cdb541a31ef8eb66d8cd1050605be9dcd74199cbd22ac739bc", size = 23508512, upload-time = "2025-10-28T17:36:29.731Z" }, - { url = "https://files.pythonhosted.org/packages/1f/60/c45a12b98ad591536bfe5330cb3cfe1850d7570259303563b1721564d458/scipy-1.16.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3c820ddb80029fe9f43d61b81d8b488d3ef8ca010d15122b152db77dc94c22", size = 33413639, upload-time = "2025-10-28T17:36:37.982Z" }, - { url = "https://files.pythonhosted.org/packages/71/bc/35957d88645476307e4839712642896689df442f3e53b0fa016ecf8a3357/scipy-1.16.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d3837938ae715fc0fe3c39c0202de3a8853aff22ca66781ddc2ade7554b7e2cc", size = 35704729, upload-time = "2025-10-28T17:36:46.547Z" }, - { url = "https://files.pythonhosted.org/packages/3b/15/89105e659041b1ca11c386e9995aefacd513a78493656e57789f9d9eab61/scipy-1.16.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:aadd23f98f9cb069b3bd64ddc900c4d277778242e961751f77a8cb5c4b946fb0", size = 36086251, upload-time = "2025-10-28T17:36:55.161Z" }, - { url = "https://files.pythonhosted.org/packages/1a/87/c0ea673ac9c6cc50b3da2196d860273bc7389aa69b64efa8493bdd25b093/scipy-1.16.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b7c5f1bda1354d6a19bc6af73a649f8285ca63ac6b52e64e658a5a11d4d69800", size = 38716681, upload-time = "2025-10-28T17:37:04.1Z" }, - { url = "https://files.pythonhosted.org/packages/91/06/837893227b043fb9b0d13e4bd7586982d8136cb249ffb3492930dab905b8/scipy-1.16.3-cp314-cp314-win_amd64.whl", hash = "sha256:e5d42a9472e7579e473879a1990327830493a7047506d58d73fc429b84c1d49d", size = 39358423, upload-time = "2025-10-28T17:38:20.005Z" }, - { url = "https://files.pythonhosted.org/packages/95/03/28bce0355e4d34a7c034727505a02d19548549e190bedd13a721e35380b7/scipy-1.16.3-cp314-cp314-win_arm64.whl", hash = "sha256:6020470b9d00245926f2d5bb93b119ca0340f0d564eb6fbaad843eaebf9d690f", size = 26135027, upload-time = "2025-10-28T17:38:24.966Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6f/69f1e2b682efe9de8fe9f91040f0cd32f13cfccba690512ba4c582b0bc29/scipy-1.16.3-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:e1d27cbcb4602680a49d787d90664fa4974063ac9d4134813332a8c53dbe667c", size = 37028379, upload-time = "2025-10-28T17:37:14.061Z" }, - { url = "https://files.pythonhosted.org/packages/7c/2d/e826f31624a5ebbab1cd93d30fd74349914753076ed0593e1d56a98c4fb4/scipy-1.16.3-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:9b9c9c07b6d56a35777a1b4cc8966118fb16cfd8daf6743867d17d36cfad2d40", size = 29400052, upload-time = "2025-10-28T17:37:21.709Z" }, - { url = "https://files.pythonhosted.org/packages/69/27/d24feb80155f41fd1f156bf144e7e049b4e2b9dd06261a242905e3bc7a03/scipy-1.16.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:3a4c460301fb2cffb7f88528f30b3127742cff583603aa7dc964a52c463b385d", size = 21391183, upload-time = "2025-10-28T17:37:29.559Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d3/1b229e433074c5738a24277eca520a2319aac7465eea7310ea6ae0e98ae2/scipy-1.16.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:f667a4542cc8917af1db06366d3f78a5c8e83badd56409f94d1eac8d8d9133fa", size = 23930174, upload-time = "2025-10-28T17:37:36.306Z" }, - { url = "https://files.pythonhosted.org/packages/16/9d/d9e148b0ec680c0f042581a2be79a28a7ab66c0c4946697f9e7553ead337/scipy-1.16.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f379b54b77a597aa7ee5e697df0d66903e41b9c85a6dd7946159e356319158e8", size = 33497852, upload-time = "2025-10-28T17:37:42.228Z" }, - { url = "https://files.pythonhosted.org/packages/2f/22/4e5f7561e4f98b7bea63cf3fd7934bff1e3182e9f1626b089a679914d5c8/scipy-1.16.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4aff59800a3b7f786b70bfd6ab551001cb553244988d7d6b8299cb1ea653b353", size = 35798595, upload-time = "2025-10-28T17:37:48.102Z" }, - { url = "https://files.pythonhosted.org/packages/83/42/6644d714c179429fc7196857866f219fef25238319b650bb32dde7bf7a48/scipy-1.16.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:da7763f55885045036fabcebd80144b757d3db06ab0861415d1c3b7c69042146", size = 36186269, upload-time = "2025-10-28T17:37:53.72Z" }, - { url = "https://files.pythonhosted.org/packages/ac/70/64b4d7ca92f9cf2e6fc6aaa2eecf80bb9b6b985043a9583f32f8177ea122/scipy-1.16.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ffa6eea95283b2b8079b821dc11f50a17d0571c92b43e2b5b12764dc5f9b285d", size = 38802779, upload-time = "2025-10-28T17:37:59.393Z" }, - { url = "https://files.pythonhosted.org/packages/61/82/8d0e39f62764cce5ffd5284131e109f07cf8955aef9ab8ed4e3aa5e30539/scipy-1.16.3-cp314-cp314t-win_amd64.whl", hash = "sha256:d9f48cafc7ce94cf9b15c6bffdc443a81a27bf7075cf2dcd5c8b40f85d10c4e7", size = 39471128, upload-time = "2025-10-28T17:38:05.259Z" }, - { url = "https://files.pythonhosted.org/packages/64/47/a494741db7280eae6dc033510c319e34d42dd41b7ac0c7ead39354d1a2b5/scipy-1.16.3-cp314-cp314t-win_arm64.whl", hash = "sha256:21d9d6b197227a12dcbf9633320a4e34c6b0e51c57268df255a0942983bac562", size = 26464127, upload-time = "2025-10-28T17:38:11.34Z" }, -] - -[[package]] -name = "scs" -version = "3.2.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "scipy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0c/c0/b894547702586a252f8c417e0c77111c9d2ae1d69c4a7751eb505e4fdb62/scs-3.2.9.tar.gz", hash = "sha256:df9542d435d21938ed09494a6c525a9772779902b61300961e16890a2df7f572", size = 1690742, upload-time = "2025-10-12T20:20:21.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/47/cf86c988b341dd1dd59661f29b87756ccd67952c706937257b51775c0251/scs-3.2.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6b585d33069829a16ef80bedd976fc6eee6e1287324f218ef6995f40e84a4566", size = 95653, upload-time = "2025-10-12T20:19:45.992Z" }, - { url = "https://files.pythonhosted.org/packages/2a/38/eb3b2d98aa5a24e6b4752520c220568e065809d02707336756e602dbdd93/scs-3.2.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c372807c261f3791b21b83d0a631f2a3bb79b73f16d9087dc289ea90560f59b1", size = 5069833, upload-time = "2025-10-12T20:19:47.056Z" }, - { url = "https://files.pythonhosted.org/packages/3d/ef/26238d2f0e851ffbb73d0c34c5b59245229af6c8b979a959fda9ab5278ca/scs-3.2.9-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9835c50081dfc270735fe339cced27ce2818383ea779fc6c673c885b0cdf849f", size = 12078832, upload-time = "2025-10-12T20:19:49.112Z" }, - { url = "https://files.pythonhosted.org/packages/2e/b8/b29c2813487c8718c679db2986ef27b13d4169696dd084ffab110cb34060/scs-3.2.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5188d3b77f618c321bcb9486a0864e39dea2774d8a52ed9b8355d7dc42f5ee77", size = 11972927, upload-time = "2025-10-12T20:19:51.153Z" }, - { url = "https://files.pythonhosted.org/packages/ea/02/97813588bd4cb26f45c293899dd2834e25b019724a390e1a224c4f128396/scs-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:6c75f835df827e8a9e1c19668fa4b21d4b7047017d19ceab4e98db2506acc466", size = 7458828, upload-time = "2025-10-12T20:19:52.98Z" }, - { url = "https://files.pythonhosted.org/packages/7c/8f/cf5e0414e2dfcd2fea25b6653ae1f94dc3221d0df6d0ddd3e345f1930039/scs-3.2.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f34aa0fb3776b546e4d3346a367fe32b72f9b5b302ec42cbb6ba157ee987f566", size = 95682, upload-time = "2025-10-12T20:19:54.375Z" }, - { url = "https://files.pythonhosted.org/packages/5d/d2/bc9b66c50d3bbec7bd51d78261d6b79ef02be170e8694b303efea79d7956/scs-3.2.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f884952d4faf9b9e7bdaa19b9b9563955c8e27f37fdf271354e2eb28d98bac0", size = 5069860, upload-time = "2025-10-12T20:19:55.723Z" }, - { url = "https://files.pythonhosted.org/packages/cc/7b/55bdd5f88e3abdee29bcae2a2dad907bdcac24ec79f005d372abae551e6a/scs-3.2.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f25e461f52d7d3128583a64ac8b724b976b7e18bc1f04ae98b3b75a5c11a7e2", size = 12078906, upload-time = "2025-10-12T20:19:57.78Z" }, - { url = "https://files.pythonhosted.org/packages/db/f9/036942285ea56febea84149aae7aed28451d0d7727af31f951da9beee6a5/scs-3.2.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0667f1ec3f4c141ee877531ef2e4568b82633b8a41de29c8341279d7e8e7ef5c", size = 11972938, upload-time = "2025-10-12T20:19:59.814Z" }, - { url = "https://files.pythonhosted.org/packages/03/76/3733c2bf1c2022d6bad92ed2a0146e2129ef992afa87708d20b1b36c5a1d/scs-3.2.9-cp314-cp314-win_amd64.whl", hash = "sha256:feb0a7e29bd26285270a9882d1bdd4b1e981a4e9cdb8eaee5f967a47bb2882ff", size = 7549101, upload-time = "2025-10-12T20:20:02.122Z" }, - { url = "https://files.pythonhosted.org/packages/a5/1a/e6a1049e741a541a675f37424aaa6461476ab5c3833858b87437154dc87a/scs-3.2.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d8573e25bc85ef77ba43bb849b4a771aeb9eb1ad43497aa181d773cc543e9a39", size = 96375, upload-time = "2025-10-12T20:20:03.444Z" }, - { url = "https://files.pythonhosted.org/packages/58/e3/9ada9f242906c0abc642e3e70cb4b65f311bdaadfb83fbd063b581a7c7b6/scs-3.2.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71d02756334b2263c7514604910000bffc016e148ef9a5a8eeeaaf52ec66f506", size = 5070943, upload-time = "2025-10-12T20:20:04.824Z" }, - { url = "https://files.pythonhosted.org/packages/36/75/c11551cebba8f36ce46a32cdc71c808b03aeb601c441fc194fe31d526ab4/scs-3.2.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4328aa741df45b3632253028f516d73f77081f372f90cdefeb3b94f4f7504ea4", size = 12079147, upload-time = "2025-10-12T20:20:06.266Z" }, - { url = "https://files.pythonhosted.org/packages/0d/94/c659c0442b0386bca295f7d5e8bae1b59af12d29370bd590b00cc2ddf730/scs-3.2.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1e786a28f942f5b0b5a28af552a6cb882b366cee4b9271267d147796d71e60d0", size = 11973255, upload-time = "2025-10-12T20:20:08.212Z" }, - { url = "https://files.pythonhosted.org/packages/27/d4/752ee94d27a400199b6fd952fe5f0253ae4b9eff565b3c6476fa6378f827/scs-3.2.9-cp314-cp314t-win_amd64.whl", hash = "sha256:23577f318d25cd623fedbe7f3330189f6d5f82c855db08e3b32bf77f43efdc4b", size = 7549595, upload-time = "2025-10-12T20:20:11.209Z" }, -] - -[[package]] -name = "setuptools" -version = "80.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] From bd4d7f2dc81219755d2d8bc0659eb4a234f64c80 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 14:37:16 +0000 Subject: [PATCH 47/52] update check version workflow to work with md files --- bin/check_version.py | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/bin/check_version.py b/bin/check_version.py index 996d4e5..3d87d16 100644 --- a/bin/check_version.py +++ b/bin/check_version.py @@ -2,9 +2,6 @@ """Check Version. Verify version has been incremented. - -Based on check_version.py from the anesthetic GitHub repository: -https://github.com/handley-lab/anesthetic """ import subprocess @@ -13,15 +10,13 @@ from packaging import version # Filestructure -readme_file = "README.rst" +readme_file = "README.md" # Utility functions -def run_on_commandline(*args): +def run_on_commandline(*args: dict) -> str: """Run the given arguments as a command on the command line.""" - return subprocess.run( - args, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE - ).stdout + return subprocess.run(args, text=True, capture_output=True).stdout def unit_incremented(version_a: str, version_b: str) -> bool: @@ -85,13 +80,13 @@ def unit_incremented(version_a: str, version_b: str) -> bool: def get_current_version() -> str: - """Get current version of package from README.rst""" - current_version = run_on_commandline("grep", ":Version:", readme_file) - current_version = current_version.split(":")[-1].strip() + """Get current version of package from README.md.""" + current_version = run_on_commandline("grep", "Version:", readme_file) + current_version = current_version.split("**")[-1].strip() return current_version -def main(): +def main() -> None: """Check version is consistent and incremented correctly.""" # Get current version from readme current_version = get_current_version() @@ -104,14 +99,27 @@ def main(): previous_version = None for line in readme_contents.splitlines(): - if ":Version:" in line: - previous_version = line.split(":")[-1].strip() + if "Version:" in line: + previous_version = line.split("**")[-1].strip() break if previous_version is None: - raise ValueError( - "Could not find version in README.rst on master branch" + print("Could not find version in README.md on master branch") + print("Trying README.rst...") + readme_rst = "README.rst" + readme_contents = run_on_commandline( + "git", "show", "remotes/origin/master:" + readme_rst ) + for line in readme_contents.splitlines(): + if ":Version:" in line: + previous_version = line.split(":")[-1].strip() + break + if previous_version is None: + sys.stderr.write( + "Could not find version in README.md" + + "or README.rst on master branch.\n" + ) + sys.exit(1) # Check versions have been incremented if not unit_incremented(current_version, previous_version): @@ -127,4 +135,4 @@ def main(): if __name__ == "__main__": - main() + main() \ No newline at end of file From 748b4b29a12d5d999984761eeecd1c79d260ee51 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 14:37:31 +0000 Subject: [PATCH 48/52] adding some bits to help with install --- pyproject.toml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4cf44fd..8091683 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,11 @@ +[build-system] +requires = ["setuptools>=77.0", "wheel"] +build-backend = "setuptools.build_meta" + [project] name = "maxsmooth" -version = "0.1.0" -description = "Add your description here" +version = "2.0.0" +description = "Derivative-constrained function fitting." readme = "README.md" requires-python = ">=3.13" dependencies = [ @@ -13,6 +17,10 @@ dependencies = [ "scipy>=1.16.3", ] +[tool.setuptools.packages.find] +where = ["."] +include = ["maxsmooth*"] + [project.optional-dependencies] dev = [ "pytest", From d8e4d930c355d775848d12529bc69cfb1d96bfe3 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 15:08:49 +0000 Subject: [PATCH 49/52] api reference --- docs/api-reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/api-reference.md b/docs/api-reference.md index e69de29..2b0735d 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -0,0 +1,9 @@ +# API Reference + +::: maxsmooth.qp + +::: maxsmooth.utils + +::: maxsmooth.models + +::: maxsmooth.derivatives \ No newline at end of file From a9578639dc1aea2ef794b3e3370146ad27103799 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 15:09:01 +0000 Subject: [PATCH 50/52] lowering python version number --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8091683..8441bc9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,14 +7,13 @@ name = "maxsmooth" version = "2.0.0" description = "Derivative-constrained function fitting." readme = "README.md" -requires-python = ">=3.13" +requires-python = ">=3.10" dependencies = [ "jax>=0.8.0", "jaxopt>=0.8.5", "matplotlib>=3.10.7", "numpy>=2.3.4", "progressbar>=2.5", - "scipy>=1.16.3", ] [tool.setuptools.packages.find] From d4be90e7819cd9bf8757403de803ecf97ab44bb4 Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 15:16:01 +0000 Subject: [PATCH 51/52] allow users to define the lowest constrained derivative --- maxsmooth/qp.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/maxsmooth/qp.py b/maxsmooth/qp.py index f6ae976..2726481 100755 --- a/maxsmooth/qp.py +++ b/maxsmooth/qp.py @@ -20,6 +20,7 @@ def qp( pivot_point: int, function: Callable, basis_function: Callable, + lowest_constrained_derivative: int = 2, ) -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray]: """Set up and solve the quadratic programming problem for maxsmooth. @@ -30,6 +31,9 @@ def qp( pivot_point (int): Index of the pivot point. function (Callable): The model funciton from `maxsmooth.models`. basis_function (Callable): The basis function to use. + lowest_constrained_derivative (int): The lowest derivative to + apply the constraints to. + Returns: jnp.ndarray: state of the solver for each sign combination. @@ -45,7 +49,7 @@ def qp( c = -jnp.dot(basis.T, y) G = derivative_prefactors(function, x, x_pivot, y_pivot, jnp.ones(N), N)[ - 2: + lowest_constrained_derivative: ] G = jnp.array(G) g_norm = jnp.linalg.norm(G, axis=2, keepdims=True) @@ -105,6 +109,7 @@ def qpsignsearch( pivot_point: int, function: Callable, basis_function: Callable, + lowest_constrained_derivative: int = 2, key: jnp.ndarray = jax.random.PRNGKey(0), ) -> tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray]: """Set up and solve the quadratic programming problem for maxsmooth. @@ -122,6 +127,8 @@ def qpsignsearch( function (Callable): The model funciton from `maxsmooth.models`. basis_function (Callable): The basis function to use. key (jnp.ndarray): JAX random key. + lowest_constrained_derivative (int): The lowest derivative to + apply the constraints to. Returns: jnp.ndarray: state of the solver for each sign combination. @@ -161,7 +168,7 @@ def dcf( c = -jnp.dot(basis.T, y) G = derivative_prefactors(function, x, x_pivot, y_pivot, jnp.ones(N), N)[ - 2: + lowest_constrained_derivative: ] # square root of sum of squares of each row From 07d16c6e914c84ad56aeb44b825024c7075474cb Mon Sep 17 00:00:00 2001 From: htjb Date: Fri, 16 Jan 2026 15:16:46 +0000 Subject: [PATCH 52/52] rmoving old tests --- tests/test_best_basis.py | 74 -------- tests/test_chi_dist_plotter.py | 217 ----------------------- tests/test_param_plotter.py | 303 --------------------------------- 3 files changed, 594 deletions(-) delete mode 100644 tests/test_best_basis.py delete mode 100644 tests/test_chi_dist_plotter.py delete mode 100644 tests/test_param_plotter.py diff --git a/tests/test_best_basis.py b/tests/test_best_basis.py deleted file mode 100644 index 40d78af..0000000 --- a/tests/test_best_basis.py +++ /dev/null @@ -1,74 +0,0 @@ -import numpy as np -import os -import shutil -import pytest -from maxsmooth.best_basis import basis_test - -def test_keywords(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(0, 1, Ndat) - y = 1 + x + x**2 + x**3 - - with pytest.raises(Exception): - basis_test(x, y, colour='pink') - with pytest.raises(Exception): - basis_test(x, y, fit_type='pink') - with pytest.raises(Exception): - basis_test(x, y, base_dir='output_files') - with pytest.raises(Exception): - basis_test(x, y, base_dir=5) - with pytest.raises(Exception): - basis_test(x, y, N='banana') - with pytest.raises(Exception): - basis_test(x, y, N=[3.3]) - with pytest.raises(Exception): - basis_test(x, y, pivot_point='banana') - with pytest.raises(Exception): - basis_test(x, y, pivot_point=112) - with pytest.raises(Exception): - basis_test(x, y, constraints='banana') - with pytest.raises(Exception): - basis_test(x, y, constraints=16) - with pytest.raises(Exception): - basis_test(x, y, zero_crossings=[6.6, 7.2]) - with pytest.raises(Exception): - basis_test(x, y, constraints=5, zero_crossings=[3]) - with pytest.raises(Exception): - basis_test(x, y, chi_squared_limit='banana') - with pytest.raises(Exception): - basis_test(x, y, cap=45.5) - with pytest.raises(Exception): - basis_test(x, y, cvxopt_maxiter=22.2) - -def test_directory(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(0,1,Ndat) - y = 1 + x + x**2 + x**3 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - basis_test(x, y, base_dir='new_dir/', N=[4, 5], pivot_point=0) - - assert(os.path.exists('new_dir/') is True) - assert(os.path.exists('new_dir/Basis_functions.pdf') is True) - -def test_loglog(): - - Ndat = 100 - x = np.linspace(50, 150, Ndat) - y = 5e7*x**(-2.5) - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - basis_test(x, y, base_dir='new_dir/', N=[4, 5], chi_squared_limit=200) - - assert(os.path.exists('new_dir/') is True) - assert(os.path.exists('new_dir/Basis_functions.pdf') is True) diff --git a/tests/test_chi_dist_plotter.py b/tests/test_chi_dist_plotter.py deleted file mode 100644 index 38e16cb..0000000 --- a/tests/test_chi_dist_plotter.py +++ /dev/null @@ -1,217 +0,0 @@ -import numpy as np -from maxsmooth.chidist_plotter import chi_plotter -from maxsmooth.DCF import smooth -import pytest -import os -import shutil - -def test_keywords(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(0,1,Ndat) - y = 1 + x + x**2 + x**3 - - N = 4 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - smooth(x, y, N, base_dir='new_dir/', data_save=True) - - with pytest.raises(Exception): - chi_plotter(N='Banana', base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N=3.3, base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, base_dir='new_dir') - with pytest.raises(Exception): - chi_plotter(N, base_dir=5) - with pytest.raises(Exception): - chi_plotter(N, color='pink', base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, constraints=4.3, base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, constraints=7, base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, zero_crossings=[3.3], base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, zero_crossings=[1], base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, zero_crossings='string', base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, fit_type='pink', base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, chi_squared_limit='banana', base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, cap=5.5, base_dir='new_dir/') - with pytest.raises(Exception): - chi_plotter(N, plot_limits='pink', base_dir='new_dir/') - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - with pytest.raises(Exception): - chi_plotter(N, base_dir='new_dir/') - -def test_directory(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(0,1,Ndat) - y = 1 + x + x**2 + x**3 - - N = 4 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - smooth(x, y, N, base_dir='new_dir/') - - with pytest.raises(Exception): - chi_plotter(N) - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - smooth(x, y, N, base_dir='new_dir/', data_save=True) - - if os.path.isdir('new_dir/Output_Signs/'): - shutil.rmtree('new_dir/Output_Signs/') - - with pytest.raises(Exception): - chi_plotter(N, base_dir='new_dir/') - -def test_files(): - - Ndat = 100 - x = np.linspace(50, 150, Ndat) - y = 5e7*x**(-2.5) - - N = 4 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - smooth( - x, y, N, base_dir='new_dir/', - data_save=True, model_type='log_polynomial') - - plot = chi_plotter(N, base_dir='new_dir/') - - assert(plot.chi is None) - assert(plot.cap == ((2**(N-2))//N) + N) - assert(os.path.exists('new_dir/chi_distribution.pdf') is True) - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - smooth(x, y, N, base_dir='new_dir/', data_save=True, fit_type='qp') - - plot = chi_plotter(N, base_dir='new_dir/', fit_type='qp') - - assert(plot.chi is None) - assert(plot.cap == ((2**(N-2))//N) + N) - assert(os.path.exists('new_dir/chi_distribution.pdf') is True) - -def test_chi(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(50, 150, Ndat) - y = 5e7*x**(-2.5) - - N = 4 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - smooth( - x, y, N, base_dir='new_dir/', data_save=True, - model_type='loglog_polynomial', fit_type='qp') - - def model(x, N, params): - y_sum = 10**(np.sum([ - params[i]*np.log10(x)**i - for i in range(N)], - axis=0)) - return y_sum - - parameters = np.loadtxt( - 'new_dir/Output_Parameters/4_qp.txt') - - chi_out = [] - for i in range(len(parameters)): - chi_out.append(np.sum((y - model(x, N, parameters[i]))**2)) - chi_out = np.array(chi_out) - - plot = chi_plotter(N, base_dir='new_dir/', chi=chi_out, - fit_type='qp') - - assert(np.all(plot.chi == chi_out)) - assert(plot.chi_squared_limit == 2*min(chi_out)) - assert(os.path.exists('new_dir/chi_distribution.pdf') is True) - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - smooth( - x, y, N, base_dir='new_dir/', data_save=True, - model_type='loglog_polynomial') - - parameters = np.loadtxt( - 'new_dir/Output_Parameters/4_qp-sign_flipping.txt') - - chi_out = [] - for i in range(len(parameters)): - chi_out.append(np.sum((y - model(x, N, parameters[i]))**2)) - chi_out = np.array(chi_out) - - plot = chi_plotter(N, base_dir='new_dir/', chi=chi_out) - - assert(np.all(plot.chi == chi_out)) - assert(plot.chi_squared_limit == 2*min(chi_out)) - assert(os.path.exists('new_dir/chi_distribution.pdf') is True) - -def test_ifp(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(-1, 1, Ndat) - y = 1 + x + x**2 + x**3 + np.random.normal(0, 0.05, 100) - - N = 10 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - sol = smooth( - x, y, N, zero_crossings=[4, 5, 6], constraints=1, base_dir='new_dir/', - data_save=True) - - chi_plotter(N, base_dir='new_dir/', zero_crossings=[4, 5, 6], constraints=1) - assert(os.path.exists('new_dir/chi_distribution.pdf') is True) - -def test_limits(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(-1, 1, Ndat) - y = 1 + x + x**2 + x**3 + np.random.normal(0, 0.05, 100) - - N = 10 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - sol = smooth(x, y, N, base_dir='new_dir/', data_save=True) - - chi_plotter( - N, base_dir='new_dir/', cap=10, chi_squared_limit=1e4, - plot_limits=True) - assert(os.path.exists('new_dir/chi_distribution.pdf') is True) diff --git a/tests/test_param_plotter.py b/tests/test_param_plotter.py deleted file mode 100644 index 869d422..0000000 --- a/tests/test_param_plotter.py +++ /dev/null @@ -1,303 +0,0 @@ -import numpy as np -import math -import pytest -import os -import shutil -from maxsmooth.DCF import smooth -from maxsmooth.parameter_plotter import param_plotter - -def test_keywords(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(0,1,Ndat) - y = 1 + x + x**2 + x**3 - - N = 4 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - res = smooth(x, y, N, base_dir='new_dir/', data_save=True) - - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, color='pink') - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, 5.5) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, model_type='banana') - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, pivot_point='string') - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, pivot_point=len(x)+10) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, base_dir=5) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, base_dir='string') - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, constraints=3.3) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, constraints=20) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, zero_crossings=[3.3]) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, zero_crossings=[1]) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, samples=50.2) - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, width='string') - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, warnings='string') - with pytest.raises(Exception): - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, gridlines=9) - -def test_files(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(0,1,Ndat) - y = 1 + x + x**2 + x**3 - - N = 6 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - res = smooth(x, y, N, zero_crossings=[4]) - - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, base_dir='new_dir/', samples=10, zero_crossings=[4]) - - assert(os.path.exists('new_dir/') is True) - assert(os.path.exists('new_dir/Parameter_plot.pdf') is True) - - N = 10 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - res = smooth(x, y, N) - - param_plotter( - res.optimum_params, res.optimum_signs, - x, y, N, base_dir='new_dir/', samples=10, gridlines=True) - - assert(os.path.exists('new_dir/') is True) - assert(os.path.exists('new_dir/Parameter_plot.pdf') is True) - -def test_new_basis(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(-1, 1, Ndat) - y = 1 + x + x**2 + x**3 + np.random.normal(0, 0.05, 100) - - N = 4 - - arguments = [x[-1]*10, y[-1]*10] - - def basis_functions(x, y, pivot_point, N, *args): - - phi = np.empty([len(x), N]) - for h in range(len(x)): - for i in range(N): - phi[h, i] = args[1]*(x[h]/args[0])**i - - return phi - - def model(x, y, pivot_point, N, params, *args): - - y_sum = args[1]*np.sum([ - params[i]*(x/args[0])**i - for i in range(N)], axis=0) - - return y_sum - - def derivative(m, x, y, N, pivot_point, params, *args): - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = args[1]*math.factorial(m+i) / \ - math.factorial(i) * \ - params[int(m)+i]*(x)**i / \ - (args[0])**(i + 1) - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - - def derivative_pre(m, x, y, N, pivot_point, *args): - - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = args[1]*math.factorial(m+i) / \ - math.factorial(i) * \ - (x)**i / \ - (args[0])**(i + 1) - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - - sol = smooth(x, y, N, basis_functions=basis_functions, model=model, - derivatives=derivative, der_pres=derivative_pre, args=arguments) - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - param_plotter( - sol.optimum_params, sol.optimum_signs, - x, y, N, samples=10, base_dir='new_dir/', - basis_functions=basis_functions, - model=model, - derivatives=derivative, der_pres=derivative_pre, args=arguments) - - assert(os.path.exists('new_dir/') is True) - assert(os.path.exists('new_dir/Parameter_plot.pdf') is True) - - with pytest.raises(Exception): - param_plotter( - sol.optimum_params, sol.optimum_signs, - x, y, N, samples=10, base_dir='new_dir/', - basis_functions=basis_functions, - model=None, - derivatives=derivative, der_pres=derivative_pre, args=arguments) - -def test_new_basis_without_args(): - - np.random.seed(0) - - Ndat = 100 - x = np.linspace(-1, 1, Ndat) - y = 1 + x + x**2 + x**3 + np.random.normal(0, 0.05, 100) - - N = 4 - - def basis_functions(x, y, pivot_point, N, *args): - - phi = np.empty([len(x), N]) - for h in range(len(x)): - for i in range(N): - phi[h, i] = (x[h])**i - - return phi - - def model(x, y, pivot_point, N, params, *args): - - y_sum = np.sum([ - params[i]*(x)**i - for i in range(N)], axis=0) - - return y_sum - - def derivative(m, x, y, N, pivot_point, params, *args): - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = math.factorial(m+i) / \ - math.factorial(i) * \ - params[int(m)+i]*(x)**i - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - - def derivative_pre(m, x, y, N, pivot_point, *args): - - mth_order_derivative = [] - for i in range(N): - if i <= m - 1: - mth_order_derivative.append([0]*len(x)) - for i in range(N - m): - mth_order_derivative_term = math.factorial(m+i) / \ - math.factorial(i) * \ - (x)**i - mth_order_derivative.append( - mth_order_derivative_term) - - return mth_order_derivative - - sol = smooth(x, y, N, basis_functions=basis_functions, model=model, - derivatives=derivative, der_pres=derivative_pre) - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - param_plotter( - sol.optimum_params, sol.optimum_signs, - x, y, N, samples=10, base_dir='new_dir/', - basis_functions=basis_functions, - model=model, - derivatives=derivative, der_pres=derivative_pre) - - assert(os.path.exists('new_dir/') is True) - assert(os.path.exists('new_dir/Parameter_plot.pdf') is True) - - with pytest.raises(Exception): - param_plotter( - sol.optimum_params, sol.optimum_signs, - x, y, N, samples=10, base_dir='new_dir/', - basis_functions=basis_functions, - model=None, - derivatives=derivative, der_pres=None) - -def test_loglog(): - - Ndat = 100 - x = np.linspace(50, 150, Ndat) - y = 5e7*x**(-2.5) - - N = 4 - - if os.path.isdir('new_dir/'): - shutil.rmtree('new_dir/') - - sol = smooth(x, y, N, model_type='loglog_polynomial') - - param_plotter( - sol.optimum_params, sol.optimum_signs, - x, y, N, samples=10, base_dir='new_dir/', - model_type='loglog_polynomial', data_plot=True, center_plot=True) - - assert(os.path.exists('new_dir/Parameter_plot.pdf') is True)

k7h7e*S4fHc4on2Op0*-+8P+Y+%fQVmkk{V3URM*Z=fSf_p3*u6A@(7&! zd8}e!A{ln zs1y&0cY`z~iWt+J5j6_&qXuyvy?L&O~iLU78CDOwHImYSG zIoI4O(L+$U`c)oX=aBJ}gIC039^YUTpr?amH&iff_yJDn2f!*nkmUglA-Bh+sKmd3 z)4fjYP0jprFLoBZ`k(QASk)`nqJ~BNtFsecs9VHI6MG{^;d%edz6Z4bnkl&-H)8F@ zj{^9NK!f#a?j1uv{Fgpj0sv~F&)0flKx}}W*uauM_Kc(>1wfl}UE*k(vlt^j>H&(q zhZO#qf_S>YaH3oNYX(pg&_WRe=U)f5?Z1Nr@}L&0qvL=%feQh69)=2)e`JGxl&>Kl zoD-!IFWgTF`{*?B{yG3-{d1TE{`tm|AyvRXhquH|#%6=L#g4}@5hvF@1AV>Zw(d-^ zR4Imq>ArJQ3;To|e^!O`7JKP_*ttLFLRKUTW2`WXQ+vms+mXVOt$FZnu6Un34RSl6 ziDQ5!j#a4u>R~C}hi>&evLM-itnS@&>{k6UJjfk7mdBsb8#u?f&5djt^fiV<=tVrb zASk)9Gp>X7ByoNYG_Yz90p|#Pk@U64A|`Np9|!3Wl8}hY5@1zSsU%1|1QIc`dw*ZZ&Z2`w-~8 z6iX8IzcDQ%D!)(5s)6= zMMd}(-U)C_N*On(zE+)#ggq`>e_N)`wO{$}F0l?^WkzIrb#q-qf)uJ0083p_LphYc zrA(qZ!Y?KFA_$=m66(mYnEEim3&3Nv=K^gH`EK>$!Y7hUfYC^L|6X=^dAWuOV)SyY z|9f^nTC_6*Ov%X!Dg18#&q=H*Xw?Kj@!9Nx zGAZUa+u^e=s=*>|3%A~?Kw(qw_(;vm?~RRWlPpk1Bm(k{a`R_DikCZ8RX;$YXuH3M zVX5KlocYpt6J(8$yi1Spb-%M0au7j`_ZO6OTZn@kh3F-a7{{uoW@gWXM@Kh?em|lR z$bQKHUCX};mR^_}d`O-LY9CA&-(MA115%K15ZL#?{vfbl1&(9fCmx+04-Y6rn`cct zF$VXl2q;_#yXJq49Hzqr65U}k|6A48padNA{}#!(FxRxr7L2jGor?;S(Z25RV0mM6 zt_;mggzU}BP$Sd|+RrK2q+L2US0R7*zXeBv8HY@=p|s)vGqcs&?;$ilwcm5GKFlkC zLngfu;5pP)WuwuJzFmnX5Nj95s_Y+pp0w=xWa?FVyTicMpia8A?T0?(9Kg;Lg|aMz zyF(8)Mo!2iZEvntO~0&eEcTIVTWsht zBZ?||sDK8k&hb6AMZ5+apGC=2c$5og3#V?D-Y(l&&M+}dNPpN5QeG@fa|!5skk_Do zlCk;A18OM4F`E(YY%I1HPd#LtFAMpnn^L zx}}>z>t?{pWer&X@yW^G-P!j(st4k|zB|Xt=5$CA6n<5{3JHNMeTb_earUhuyW7|9 zm5r&4L(1{#>3jzA_XQP#-KIZQrH;K&`pS6VK=_=`?q+)~!->mbU~v|wjCQ+OOjLnL zd~pk?#5Av+MVZ|eaOaEQ9^*59^EtX0u$rg>t64B#d1%v%&e=2&whoK(D9oo|CD)4Z zTv9@mkYPp#o3v+V_ZXDwePo4=F)==_G)H0oB5Ue9i%ELPir!*QhF99aDvh&26E^H! zL&N2n{t|tNGxKsGZKyt4#t7uOGp}jvO4sAzC}pVd705;JZjCwr9+XvXp6x3-K=t6} zx8wA<@!(8_LHP+)KJYnkaVH zPP^#m*|wqLY%PD;^}GS^qJYC^%}Nvux?;g_Xfz&NezH}U0@7e>(pAWbHlN8dZ#oJg z(_~JEp^C{w->>PyryIZceUk3o!(Iv(l1GD3509ed?kgP!vMwA?Bvz1##~SdHd9vtw&kS!u;Qu(zw0j_`qjohTKLASOyt2U+O zjm~wnoKre0II1 zHpXLvAC{(566~{|KBbzP16~BJJ`{EMDJQk{yW*gcl$cl@uQ6nens3ukgLp`?PE1Txg2N#R9RLdwz8$l>L*f+; zLeBE&G z)q~lKHmMCtRfJ)eC_h~{q%}1FKAQ1=D~@A3r1G%;GUR&a^}DNl`}XaPpvl86Zy(jj znSnAR3Oe?<2J186GEh0b^%6)bF4LVi+F-*uI{o~*2R3w1_t->2v=-O?kKR|luHtAR0hH-fMNifU?t09NQURPSFc`$B}997Pj~0k0$Wgp{vFjQssPVf z|BS!X+|YAgp0nm0$Z4bBn2khG66U#JrRQqVfGFHWFi>VE-wpEN>Yt1Cn;%z;vc4QG zZF6`SR5oFs?G7IsbUvayW+fKi(|J{U&N@bCO>vs0`A$xPcO5-6u=X%1B}EvRuu(Oi zjh6)r-+AgENiQ8)gt7zus&`;GXYvNn^IQ*usDFRqQK}5UvUX{|?YgPSNujIps)A4j zECN#^3aH`?^L2Y)T__hl%yG(!R!f^=FPp&bR^zU<%S^ZF!9$1YhXZA7`3gq%JJySK z=v1*x79NGtW3-#1khy=Ho-zzl_QRPC?|z;=TF?y%QbIW6N1u0QD`vJ zP{wN`dwo*7%u@QdFI`x1@i|AxYzx2eXfM%e0{Qi#bxaMcqhP!TcUaL}X%8b4(;L*V z&IkJRP7jpHjIw|~5su#M9jmK;!C4Q>TfgwDwjL(jW=*8a=3Swsot+puEOa>Yo7-kT zzdkX8x?C^F1~;HBx$DeTvjviF&WiHL?fxFSG8+)a>V6MZT!K>20$6ZW5G)rHYHa=5 z+5oV?P_LVSs%3S@(XpOFW=+-+7|b`XU%w6;rZF{eYhYwVk%uf$GJm6_88g2q1^=7UNSgpdj(oGF_J|rAOjdHE%jn;&vpU?Ow!A^zu-yNovn*Yl1 z2GZM5TR(I4+O@de-rghpwY%#wyNW2k3GtXW>}wPaPjzHyL&>lAZ$A#2^>qqi$X|ip z@bQivJnNDQ1?eHL9Wj}*7quA435&m>80VXk5On6Sy^Qkc$13)$D7%5uKJdcfuvu0~T%|}SstWKcf5uKRhXkFvEHX8(?h(&)FKoH7rrdHYJ ziWdXW?FSy&z0CCa#*Ceh6_li0!qE$WvlgK{_ZweViauNIbB!*5IJWNbK2BB06?B7A z?RqGLs@vT#+O73x5&WVWDcRQA(V;)L4!5;L50puul$rF}XF7CiWki)z zm_aGLSyPPsD7eO{)d4nw7Z7*GZ($skaGUOIi}M(%f?;YqSnz3ZhUh^J%gzn^~7c%pNv8_X#125363p=mTzP9nq?RYj$x)*-l|Ppr$YzZ3E{Jh;J@Es2Iv0<2!x&6&J+#IgPpfziMh~)FB0K zc?-bjk1#=#B^cnUepJ~;N?CB@SXLA>GjkQ2Bl_C~kg9(1;zjh=FAO|pa)RR^yxF^< z8*AvZ?F@vI`O0)xd#=N9y=$>JM=-UWwynW zQXc@$FM}mgMw3xqO4`Mk3YOS9kW{k)>&BV@1r#6=I2aXeEz~Z5=gIiG#G0Csp|%kL zqLNPvz|%ReIS&V;z{@We09A>bJw2%04UmGbX!=vw>-@#0wzdyYk+0i`{wM}4@puKt z&TqHFU{#}#ER))-Ti4P=z(z=ICEujN zAXfxU*PJTbN!fuELVehLa?u6bkk)t->J!l0O1dv40)T8A6X)3Y@yKcTxfuE*8}1N~ zE&%|Zpf*~&#|QPL-cx(eN*zz{8yg`|Jhx_ASGGXMCM2SDY-6gM=3&4rm7VS|hX6w_2de#w8tG&?>;&N%oO!Br2q o2R%EAgzdv41Xc{`|MN*W5+Jr!w2*6h9KBpw{<2*9dEt<8 diff --git a/docs/images/combined_chi.png b/docs/images/combined_chi.png deleted file mode 100644 index f28f6b2a2a5f8f9046a46d8d790d14ac5359784b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45499 zcmZs@1yqz>*Ec@YFyH_qp+hr>2na}nk~5%$v>>Q-gLF&BP|`?Ar<62Ecd4j^A_&qV zEg&iRo$=~txZ_m&7EDW9qa{p`FZ)dS*%=L9q-(_^}oOKIyhV2LReg-g+N#!igIWz z&y0;WZyyFr->r*pNk8sqh}BTu;GbYKpi*$`x!cZwA>fIiCYP*JXZ^N!N?N3D8+JbF zGMU91|3Iv+(2lFC@~W6j!LT~VYF9F8;nI~l()p}Qni$IEpH?o_l(*kpbMR?65a^Kp z@o4jd#Lx#p!J!WuHd0&TgSVb~EdSp4wIMOPyxV3D@8Oeyp|EjUFI2oBSOf;9$V5ko z`!^Sj`yTPn2fX35J;)WoBDL&(Sqe!)h;Eyg@Z%?coTxCch*0OIDA_P_JV-_J8W;DI zHy_5&Gjdsf zMxge2gS@xeu0H+xTG3Gm4B(0&_#>?CwZAsjepm!fYV$sP%%rBKW;)&M1_=;;`qgN2 zvR)A$iNGklhf&t{a}$6|VTV~*aHH3UKCULFNmeSv-ot%+6ikW-CW9$Ptn~5}$AJT^ z&59AYdt;%0f3W)dfiMa+tfch_8p|veO66kCGr(Fvt2^^GNJrm?>2b}=f-sDNO%8gP z@cUjpG5;T1{#9cH<;}|06+IufWqPOiru#3LNKqvL(7=1C<}%?@SrVQMvz~L$PJaon z|MLq!AvP{_sq=nO0uw%}B#;zMRpq02=^?kZq8Ab?_vxiG%~Gj`w_Yid_X!oo6%(98 z(s&l^pzH<1_I3}PZyKNOP7i%yO5qwKl$TX#&KV3qjPljh>pCb3!C(;-T!eJSF4r*K zBVSEa1i3$(%P82Yqgb#)@N$vh9IZmMjDnszY8dvJoP;E-$6Wo@U_e}B4n_uMjog5u zo0NiaAHh=xANdJgqEIYsBDk>7g?@dlf-*|RLsg@L|GD8L89o;wwwH(uAEVGSoLt`m z2f?Jg3I>59lf4;CN}>n{>n1L=i%CnD3pWlu++z`f$J`+V+be?X3i~MR{#7bUa(PC4 zC=DegJ@^(y7M$NZVUZ;+c^dC0x%=nf3AF= z;Sto87L1{UA4VF2FYq#IZ+33ZXjGPsZJ)0=F7Ahdiu(MIA8dET#p4H;AP`1IM#xXH z5KL}BdwV-um^>^{Ftn2|Kxs@Svb=yFB_|E8^Q&b`Dk?TMzpZWhw~vFvt^WRgN;(=; z0h2c)zLCLot9NhM_~^(VHwW$X!6M~1z#!L5}1$=+ET361)L-h9_3DS_D^#d>h zBpqFMZ?D`(#<-#7YU|JJU1-kr{36s8zhxp5}oxC6mgh&Z8?lZ*wvBNkSLks9s~Mw zKO!n720v94vf=9Ck+072B@rSHCP6P^8}90ZMO=i}z~9>jDuWx9qm8&=tlws%m=PuL zK9kFRCh@=UF?4aswov!@0J0cZMA$1~82gPIg)f@_v~obZd_Hk2%fYOF+VjvY2Es0^{h$e;t;>@g+Qt-|$u-pcZYY(ox#jVNUS6VQwh&!rA z7w2acl|vss7_EOTkB+7d%!E}P;Vv=i37No~}gGbLy>efx=g2?)(*a^JaxEqY^A$XtD`}(V5biI`h(4-RXxG8!lqn+>icR9c4{H7p%;rkkSC*Bn zEn>*Vx7vZ7$%zRhn9(&I*v7_m%lPlDPvToq`=?lL=tf@zQcD5M=k;Lc%@<%nVqshT+V1Ki*RLXC${W5QQgS09%L zot+$t2O&sMs&A%$3w}S@!;r||&`9ytU9ifg2j}0DB zUCcN1M^Z>0QX=(};Vm9*ms1R?SmRwjvkb#bVK5SkDdrmk*%t%Xj%KdiVv~&0dQrgI zj|4eLcD`8aZBF-u=TTD%$gGM8Tn2&T22@K#^GO309xZs?@2hnv$n^!eRYi=NsBnsw z9kOjxz_wVHIK+l|IY!*-_FHEJ|%J`52W8(?|gM%=eiIbrKk{0s2fbH zyS8BLrvS$TRQRP9OjTWyv4wTetO&TW)yK&xX7F{e&6uNBNC7&Iw-{lC1@p&-S%s?Hc`>On48I5cJROZxY)2Gf-H*rx|e3f{hY& z*ntTeZ<))4urU3^lHwJG3w0s!qxnGg-mXeP3xw-I|L3r-gMoKOIxqoR%YNcV-*L&l z7PmC=Q}Cvk2ZE+qbSKm9vdadusQkqR>L`=~v}Mpp@lsJ(U6(@!7?v0relvWbGZ#_E zzr<(vH@8xk#~cg@!4^8R+!aDte7EUuV1=kZaTDNBA0N#PhyXm1&jZ48~2bo*QTJUt!M1H zBS%F%>3zxjjJp2w&kMp9A_cEMQAg1PefbMO>fvjM)75ciRV$$`-O+@;6sam29fwAi z)m#qKSX9p7f5sSzYWA(r?0Y+Octa9yI8h5gs(`|85#Z87&83G%`_BMe-?NIz$hhwX zYj@P*0uSuYiU0r_YMyWK_S3-fqwo3;QaQ7fyu{wOI&KIZ4Dm)ae5<)8*9HgJivvor z3cXs&>_6qAY~Thyt3_&yix=&2)@Ip8^o;U_7&^j|;8`&g)~b^U{_T_$?=$&l9CpD* z0&0IayKoYM%;rjKg)NLEQM~0IlJiFo%B`Q_eiTiG35QFl2au9@{@89r&ui!!KF0^84^cpAy#?yWhlpKM|mVl8<{+Acc$RLyI z@bh!O51&5e<>wRB*48%ee|<7CGn2J93`40XKdo(nPkiUtFL=+Anvu~P!zd1L0pvPj z$V8nrm3{jk3jj!L5_d2Pf~FMRPw%9lBivx4s-^ItnHdA{)0Zeb$jaJUH^_8U3^XV+ z{^7|VyaYv<&YbSLc)DOCM@K{m22WB_GI_ZKj=;DYQE&;tb2NpA6Fw>&SaIu?#1-_j zG;Xz@0HloYk&4A7ugJS#vWsk7Rt};+G)g4G=zNX?1_w-7PYD5hD|mpnG^IHfr}2Jic2!x1I+1 z`1SBjoTmyUqlc%aB0+F|{j&eD`;3~DXnd2Hn3!Kk2pbU*@iN&e zDyGKEpEB#0otqe%o13dl2gsF`mF2c$U?}UZUjmQ-=fd0gmj<;74v-35gsb_v@Synk z_{rH8k1hAEPq)O5NFtXH?YELJz3QPj<);XkZBgAiPK{Z!mkwT^70kyg&QqnfcdV5{WRhZHViaOK{4e|l7uPFVKH*SzzN9GYxhotS*WWcVSF8xf7ZG8V zp`s^j(o=oh_|`{iZ7ulectyR0yH?YXmr0|?mciiS>Z)}=Eh2%HftTPTIz&3t z>vF?sXIn-KIY=xoUY&jYxYs4=eIRB)PfsrkXvzr{0%OwmOMpXXpN=rL!%=yC$E>y0 z_ZjyxD*A2@7oovRFivt`Uthol2Hx0Baks(m$;(r%s#G~G-Wy!hETKL@0={PKLHohl zoi@=lTv4~Wfav0^dGMMvg|!4AfJg?0UceqmLog}_hV?cyU}XZLwxK}FfJAmC^E|<= zQCC;jFQf3DFIQNwaXE6E0#(GE=SBOBM-$=(`I|@Il%Y*yH`DTDuZ^h5(h}kZv%bDt z4`ddFmzNhSUA#0>Rz{(@`X*tsKJQ#ysSBbbH3#Q7;*(^cleh; z6)m#-^;H?6?y?93M(A?eV5f~y`0)({B{hKKzsFI5?;e_n4GJ@k5LdE;M2Pk6t7zfV z_~tIr!irWv;@}cUqyl=&!tQVy{C)%?dfSE-i%^ksK=6eI$Pwc(Boy3mal`#BH^HdH zzrRjz4l~Khq~MK^{JpB&7vA98^2vDmP&sB?f&~Z+F3A{VI zD+G$;{<$tt39gH-v@6=MpYN5$*+#nlnTFe{3E+R-a&k9t@SQsa(fL!k_d+@i zf+2t~?*03;3I{v0j3HGZhL`?{VIpsELXHL{h~d8zcTYhV+T?J>9S5`66e|Buu(8Fw z0aoVBgidfg8vHy8oL`VfGD67n`-~V(9s4(M|BMDC-<(@j>SnriH6VDfzd(q!>XRyZ z$AX}}0_5f$V@4b}V&9rOo=gv!Ed3T)mAaW+H>YFJM)&lS;V&;+?|zI3K^@>ObihTp zoXpG4HXZ(Os&LEuKdCftp?dlLWR`VZ!3 zU2gO(gEG{WGXJbK9P)|+uzypr)j1vVX!hiaTGP$v8>TXOII4)X`f+hOuIl6E!%P~c z+Gu|`5ojvrbE>>qt>cwSf&1G0a+1XK8wg6wuRX4%9R{L1o3LH@`rN)PVtRtVRE+a2b zY+-514`5V}H)XF1hT_csD3a?fjIL>+o;Xfjd4(bi0x~%;5Dy@OvWiNRefrSy(-+4Z z8$SGqZ)}Df)Q+E3L~{YBc(WBsM(_CJ?d7_LhIRjISOjZVF2d8Cc0!NT)>h8-vpN(F zRP^&c*5;O$cyNtJ5CQ1_VC^I}>wom>IJ+N}H^f*+=PJ-eBeS!yxw)t|hfoAYuS#v@ zz<|hoVlY5X1*EHeJpca}UB`UEX&{+~0%oG-hL=hq^kI3oi&zDQ!mGM}evpF}KNz2y zSdFuKWv%jIWJCk93k}Ew=ntS@SylCG)>Qq|t6tvTAp?0W0SHRbgB+P5WDu!7lHz%2tP;B;x$kAsbzoi&?lL~-~! z0j?-wJ7M�uTU@@CgVAM#vHo7(%f%gy+6Mu_lUTWK^A>u(@RGfl(=BdV1Q*!9gDA zdP~b9&5Xb(fI8#jmKGNH%;|`l#+~WGoDX%flsqcdh++{ofzJpPKt}4CiE#pVQx_ZO zT3s+^2*>4>FG5Q+eJnBS>efOWk#_cVL4hC3!m66>Z69EExbV0Bnz;GyKg9a8YTY2(7JA5+zW5J0LdhnNPQ znwpw|dB*CYs%mj?*YUKnP2}q?6()_?a@E9LobBCcl}@4#JDN8|*3gg{uoE7fF#-$+ z6CWRmH54UA!6>6J(icke1_TgbQA*d`91E~$04KDmxhT~xiyK_3dbVpJPml-JuI;xP zB60VP;(9@7KuJl7++#XmOTjeyG*aI>teSunEl6gL*xTO+3VUc=3NY1`)zt_qIV^&b z%j#rgJ}GkOmfQawo2lj%l30tY#bqilhB@#f>stJ8`8jg0A^ttck8-uB`rY%B|~Kj z_z;v(Try37T;3deTPfNvJ024B2o6&i85?Rp?fz;h{h&0n zU*1b;NsVhu%kl!e2?i?y!!TgRp-RnaY0U&>e4hn2{XQk|zSotun_@hWzC2iM==h6L z&%5s~$lQ~E(;&&nWI}x-R5>Ka_P%th=aPWWT-tthOmqPN1v+DO6sniP?i>8)8dEwW z8Dl0Ht&D<6KpGXuPFVc|(Xz{vPsyveP!R+M=3vZ-Jg7XRj55J2XHe!E*i+b}u3w~l zNqF8QrtTtaPMu{@2n=O+`)^TGVg^!lGAUjJ6E50+Z*uUM&;lOVR*Ry+rzCED5B4UC zfwb!zGDtHCYyv-=r>TGu3nKl9#DDV5|@K!+AL5kPUrP)2aP2!Q%@I5-Pu z-XIFIaf6kDDDCw8GwNJKh8yjNq!L8j(LZrBrnr*G1-xe#{(tB7iQbm|0Jn$vZ=iqat0Pgc6#vsadL>!?J zBYt$1CNA~|Mrc9z0H9qd|DBGjcw#SbURa!DLS(MJ)>44&^icNU_zD}jXVPU{jHvM+ zF#@NT4f=1)yl6ArXeMsb2n+`F;{9_U%j7^>Evs16TzQ(@zqf9=nZs6sqhk@lTJ(fK z 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