<jupyter_start><jupyter_text>Polynomial interpolationThis notebook demonstrates how to use PySensors to select sensor locations for polynomial interpolation using the monomial basis $1, x, x^2, x^3, \dots, x^k$. In doing so it reproduces Figure S6 from [Manhoar et al. 2018](10.1109/MCS.2018.2810460).Reference:* Manohar, Krithika, <NAME>, <NAME>, and <NAME>. "Data-driven sparse sensor placement for reconstruction: Demonstrating the benefits of exploiting known patterns." *IEEE Control Systems Magazine 38*, no. 3 (2018): 63-86.<jupyter_code>import matplotlib.pyplot as plt
import numpy as np
from scipy.linalg import lstsq

from pysensors.reconstruction import SSPOR<jupyter_output><empty_output><jupyter_text>First we construct a matrix consisting of our chosen basis modes. In this case we form a Vandermonde matrix.<jupyter_code>r = 11  # Number of basis modes
n = 1000  # Number of data points in training set
x = np.linspace(0, 1, n + 1)

# Construct Vandermonde matrix (column k is x^{k-1})
vde = np.vander(x, r, increasing=True)

# PySensor objects expect rows to correspond to examples, columns to positions
X = vde.T<jupyter_output><empty_output><jupyter_text>Next we feed this basis into a `SSPOR` object (Sparse Sensor Placement Optimization for Reconstruction), fit it to the basis, and ask it to select 10 sensor locations.<jupyter_code>model = SSPOR(n_sensors=10)
model.fit(X)
sensors = model.get_selected_sensors()
print(x[sensors])<jupyter_output>[1.    0.641 0.    0.884 0.289 0.47  0.099 0.958 0.763 0.036]<jupyter_text>Let's define a (non-polynomial) function, sample it at a few points, and attempt to fit it with the monomial (Vandermonde) basis. We'll show that using measurements taken at the points suggested by the `SSPOR` object will lead to a much better reconstruction than equi-spaced measurements.<jupyter_code># Function to be fit
f = np.abs(x**2 - 0.5)
# Interpolation using the points selected by the SSPOR
pysense_interp = model.predict(f[sensors])
# Interpolation using equi-spaced points
equi_sensors = np.arange(0, 1001, 100)
equi_interp = np.dot(vde, lstsq(vde[equi_sensors, :], f[equi_sensors])[0])
fig, axs = plt.subplots(2, 1, figsize=(10, 8), sharex=True)

axs[0].plot(x[sensors], f[sensors], 'bo')
axs[0].plot(x, f, 'k--')
axs[0].plot(x, pysense_interp, 'b-', alpha=0.5)
axs[0].set(title='Approximate Fekete Points (QR Pivots)')

axs[1].plot(x[equi_sensors], f[equi_sensors], 'ro')
axs[1].plot(x, f, 'k--')
axs[1].plot(x, equi_interp, 'r-', alpha=0.7)
axs[1].set(title='Equispaced Points', xlabel='x');<jupyter_output><empty_output><jupyter_text>Note that you can update the number of sensors at any time with the `set_number_of_sensors` function.<jupyter_code>model.set_number_of_sensors(5)
sensors = model.get_selected_sensors()

pysense_interp = model.predict(f[sensors])

fig, ax = plt.subplots(1, 1, figsize=(10, 4))
ax.plot(x[sensors], f[sensors], 'bo')
ax.plot(x, f, 'k--')
ax.plot(x, pysense_interp, 'b-', alpha=0.5)
ax.set(title='Approximate Fekete Points (QR Pivots)');<jupyter_output><empty_output><jupyter_text>To see what the reconstruction error looks like as a function of the number of sensors we select, we can use the `compute_reconstruction_error` function.<jupyter_code>sensor_range = np.arange(2, r + 1)
recon_error = model.reconstruction_error(f, sensor_range)

fig, ax = plt.subplots(1, 1, figsize=(10, 4))
ax.plot(sensor_range, recon_error, 'o-')
ax.set(
    title='Reconstruction error',
    xlabel='Number of sensors',
    ylabel='2-norm reconstruction error',
    yscale='log'
);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1255930784259001, 'fraction_numerical': 0.03572425341892269, 'mean_word_length': 5.826666666666667, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '292650', 'license': 'MIT', 'n_tokens_mistral': 1373, 'n_tokens_neox': 1268, 'n_words': 379, 'path': 'examples/vandermonde.ipynb', 'repo_name': 'Jimmy-INL/pysensors', 'size': '3613'}