<jupyter_start><jupyter_text>Simple ``maxsmooth`` Example CodeThis 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 $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,$ \frac{\delta^m y}{\delta x^m} \leq 0 ~~\mathrm{or}~~ \frac{\delta^m y}{\delta x^m} \geq 0 $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.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.The user should begin by importing the *smooth* class from *maxsmooth.DCF*.<jupyter_code>from maxsmooth.DCF import smooth<jupyter_output><empty_output><jupyter_text>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.<jupyter_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))

N = 15

import matplotlib.pyplot as plt

plt.plot(x, y)
plt.xlabel('x')
plt.ylabel('y')
plt.show()<jupyter_output><empty_output><jupyter_text>*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.<jupyter_code>res = smooth(x, y, N)<jupyter_output>#############################################################
#############################################################
----------------------OPTIMUM RESULT-------------------------
Time: 13.211431741714478
Polynomial Order: 15
Number of Constrained Derivatives: 13
Signs : [-1  1 -1  1 -1  1 -1  1 -1  1  1 -1 -1]
Objective Function Value: 0.049767752022560015
Parameters: [[ 4.93743954e+02 -1.22808736e+01  2.13803269e-01 -3.19414523e-03
   4.38004681e-05 -5.60542296e-07  6.84052878e-09 -8.93587837e-11
   1.15739748e-12 -9.46473558e-15  4.99311590e-17 -1.61222191e-18
   3.82618421e-20 -3.68041597e-22  1.28748236e-24]]
Method: qp-sign_flipping
Model: difference_polynomial
Constraints: m >= 2
Zero Crossings Used? (0 signifies Yes
 in derivative order "i"): {'0': 1, '1': 1}
-------------------------------------------------------------
#############################################################<jupyter_text>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.<jupyter_code>print('Accessing Fit Attributes:')
print('Objective Funtion Evaluations:\n', res.optimum_chi)
print('RMS:\n', res.rms)
#print('Parameters:\n', res.optimum_params)
#print('Fitted y:\n', res.y_fit)
print('Sign Combinations:\n', res.optimum_signs)
#print('Derivatives:\n', res.derivatives)

plt.plot(x, y - res.y_fit)
plt.xlabel('x', fontsize=12)
plt.ylabel(r'$\delta y$', fontsize=12)
plt.tight_layout()
plt.show()<jupyter_output>Accessing Fit Attributes:
Objective Funtion Evaluations:
 0.049767752022560015
RMS:
 0.0223086871022389
Sign Combinations:
 [-1  1 -1  1 -1  1 -1  1 -1  1  1 -1 -1]<jupyter_text>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.<jupyter_code>res = smooth(
    x, y, N, constraints=1)<jupyter_output>#############################################################
#############################################################
----------------------OPTIMUM RESULT-------------------------
Time: 17.524691343307495
Polynomial Order: 15
Number of Constrained Derivatives: 14
Signs : [ 1 -1  1 -1  1 -1  1 -1  1 -1  1 -1  1 -1]
Objective Function Value: 0.04997366530209926
Parameters: [[ 4.93743471e+02 -1.22808405e+01  2.13814758e-01 -3.19444274e-03
   4.37560407e-05 -5.59706086e-07  6.90272432e-09 -9.04292660e-11
   1.11944074e-12 -8.77169765e-15  5.93712196e-17 -1.83309620e-18
   3.79739211e-20 -3.40532152e-22  1.13892498e-24]]
Method: qp-sign_flipping
Model: difference_polynomial
Constraints: m >= 1
Zero Crossings Used? (0 signifies Yes
 in derivative order "i"): {'0': 1}
-------------------------------------------------------------
#############################################################<jupyter_text>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.<jupyter_code>plt.plot(x, y - res.y_fit)
plt.xlabel('x', fontsize=12)
plt.ylabel(r'$\delta y$', fontsize=12)
plt.tight_layout()
plt.show()<jupyter_output><empty_output><jupyter_text>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.<jupyter_code>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()<jupyter_output>#############################################################
#############################################################
----------------------OPTIMUM RESULT-------------------------
Time: 11.277308464050293
Polynomial Order: 15
Number of Constrained Derivatives: 12
Signs : [ 1 -1  1 -1  1 -1  1 -1  1  1 -1  1]
Objective Function Value: 0.04967661128564428
Parameters: [[ 4.93744160e+02 -1.22808738e+01  2.13797953e-01 -3.19410879e-03
   4.38228511e-05 -5.60764306e-07  6.80628376e-09 -8.89234642e-11
   1.18037177e-12 -9.83236755e-15  4.35392184e-17 -1.47274085e-18
   3.85498374e-20 -3.87573378e-22  1.39326338e-24]]
Method: qp-sign_flipping
Model: difference_polynomial
Constraints: m >= 3
Zero Crossings Used? (0 signifies Yes
 in derivative order "i"): {'0': 1, '1': 1, '2': 1}
-------------------------------------------------------------
#############################################################<jupyter_text>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.<jupyter_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()<jupyter_output>#############################################################
#############################################################
----------------------OPTIMUM RESULT-------------------------
Time: 3.629124641418457
Polynomial Order: 15
Number of Constrained Derivatives: 10
Signs : [-1 -1  1 -1  1 -1  1  1  1 -1]
Objective Function Value: 0.049724821013759544
Parameters: [[ 4.93744054e+02 -1.22808710e+01  2.13800665e-01 -3.19414659e-03
   4.38115602e-05 -5.60616156e-07  6.82331415e-09 -8.91658318e-11
   1.16913341e-12 -9.64513657e-15  4.66060212e-17 -1.54047402e-18
   3.84176646e-20 -3.78334129e-22  1.34361764e-24]]
Method: qp-sign_flipping
Model: difference_polynomial
Constraints: m >= 2
Zero Crossing Derivatives: [3, 4, 5]
Zero Crossings Used? (0 signifies Yes
 in derivative order "i"): {'0': 1, '1': 1, '3': 1, '4': 1, '5': 1}
-------------------------------------------------------------
#############################################################
StarcoderdataJupyterStructuredCleanDedup