This tutorial uses the same example as the example introduction.
Lagrange polynomials are not a method for creating orthogonal polynomials. Instead it is an interpolation method for creating an polynomial expansion that has the property that each polynomial interpolates exactly one point in space with the value 1 and has the value 0 for all other interpolation values.
To summarize, we need to do the following:
In [1]:
import numpy
from matplotlib import pyplot
from chaospy.example import distribution
%matplotlib inline
# Generate samples:
numpy.random.seed(1000)
samples = distribution.sample(5, rule="halton")
# Show samples as 2-dimensional scatter plot
pyplot.scatter(*samples, marker="x", color="k")
# Make scatter ficutres pretty
pyplot.xlabel("Parameter $I$ (normal)")
pyplot.ylabel("Parameter $a$ (uniform)")
pyplot.axis([1, 2, 0.1, 0.2])
pyplot.show()
In [2]:
import chaospy
polynomial_expansion = chaospy.lagrange_polynomial(samples)
polynomial_expansion[0].round(2)
Out[2]:
On can verify that the returned polynomials follows the property of evaluating 0 for all but one of the samples used in the construction as follows:
In [3]:
polynomial_expansion(*samples).round(8)
Out[3]:
In [4]:
from chaospy.example import exponential_model
model_evaluations = numpy.array([
exponential_model(sample) for sample in samples.T])
model_approximation = chaospy.sum(
model_evaluations.T*polynomial_expansion, axis=-1).T
model_approximation.shape
Out[4]:
In [5]:
from chaospy.example import coordinates
# Estimate mean and variance
expected = chaospy.E(model_approximation, distribution)
variance = chaospy.Var(model_approximation, distribution)
# Create band one standard deviation away from mean
pyplot.fill_between(coordinates, expected-variance**0.5,
expected+variance**0.5, alpha=0.3,
color="k", label="standard deviation")
pyplot.plot(coordinates, expected, "k-",
label="Estimated expected value")
# Make plot pretty
pyplot.axis([0, 10, 0, 2])
pyplot.xlabel("coordinates $t$")
pyplot.ylabel("Model evaluations $u$")
pyplot.show()
In [6]:
nodes, _ = chaospy.generate_quadrature(1, distribution)
try:
chaospy.lagrange_polynomial(nodes)
except numpy.linalg.LinAlgError as err:
error = err.args[0]
error
Out[6]:
It is impossible to avoid the issue entirely, but in the case of structured grid, it is often possible to get around the problem. To do so, the following steps can be taken:
So we begin with making marginal lagrange polynomials:
In [7]:
nodes, _ = list(zip(*[chaospy.generate_quadrature(1, marginal)
for marginal in distribution]))
expansions = [chaospy.lagrange_polynomial(nodes_)
for nodes_ in nodes]
[expansion_.round(4) for expansion_ in expansions]
Out[7]:
Then we rotate the dimensions:
In [8]:
vars_ = chaospy.variable(len(distribution))
expansions = [
expans(q0=var)
for expans, var in zip(expansions, vars_)]
[expans.round(4) for expans in expansions]
Out[8]:
And finally construct the final expansion using an outer product:
In [9]:
expansion = chaospy.outer(*expansions).flatten()
expansion.round(2)
Out[9]:
The end results can be verified to have the properties we are looking for:
In [10]:
nodes, _ = chaospy.generate_quadrature(1, distribution)
expansion(*nodes).round(8)
Out[10]: