Elliptic toy problem in 1D¶
Problem setup¶
Consider the elliptic toy boundary-value problem
with \(U = [0, 1]\) and random coefficient function \(a: U \times \Omega \rightarrow \mathbb{R}\) on \(\Omega := [-1, 1]^2\). We choose a uniform distribution for \(\omega\) on \(\Omega\). For simplicity, we choose the constant right-hand side \(g \equiv 1\) and coefficient \(a(x, \omega) = 1 + x + \Vert \omega \Vert_2^3\). Given a quantity of interest (QoI) \(q(u(\cdot, \omega)) \in \mathbb{R}\), we are interested in (approximating) the response surface
As QoI we choose the mean of the solution of the boundary-value problem over its domain \(U\), that is \(q(u(\cdot, \omega)) := \int_U u(x, \omega) \, dx\). In this case, the response surface can be expressed analytically as
with \(c = c(\omega) := \Vert \omega \Vert_2^3\), and looks something like this:

Polynomial chaos expansion (PCE)¶
Next, we want to approximate this response surface \(Q\) using PCE onto a polynomial space \(V\), which we denote by \(\Pi_V Q\). Although an explicit solution for this problem exists, we pretend we do not have access and the use of numerical solvers is unavoidable. Maybe we have implemented a response function that looks something like this:
def response(omega: np.ndarray) -> float:
# Solve the boundary-value problem
u = solve_bvp(omega)
# Compute the QoI
q = np.trapz(u, dx=1/u.size)
return q
To compute a PCE, we need to decide on the polynomial subspace to use.
Here, we choose total degree (TD) polynomial spaces of maximum degree \(m=5\) in each dimension.
We can generate the corresponding multi-index set using multichaos
as follows:
from multichaos.index_set import generate_index_set
index_set = generate_index_set("TD", max_degree=5, dim=2)
Let's also define the uniform distribution for \(\omega\) using openturns
:
Now, we can create a PCE instance using the SingleLevelPCE
class from multichaos
:
from multichaos.single_level import SingleLevelPCE
pce = SingleLevelPCE(
response=response,
dist=dist,
index_set=index_set,
)
Finally, we can run the compute_coefficients
method to compute the PCE coefficients:
Now we can evaluate the PCE on a new sample \(\omega \in \Omega\) using pce(omega)
or compute the mean of the QoI using pce.compute_mean()
.
Multi-level PCE¶
In the multi-level setting, we want to combine different levels of accuracy of the underlying numerical solver. Assume therefore we have access to a hierarchy of approximative response surfaces
where \(u_n\) is e.g., a finite-differences solution of the boundary-value problem using \(n\) discretization points. Obviously, the functions \(Q_n\) increase in both accuracy and cost as \(n\) increases. For a fixed number of levels \(L \in \mathbb{N}\), consider a sequence of increasing and sufficiently large discretization parameters \(\{n_0, \ldots, n_L\} \in \mathbb{N}^{L+1}\). Consider the telescopic sum
The multilevel idea is now to approximate each term in the sum using an independent (single-level) PCE, as introduced above. Similary, consider a sequence of increasing polynomial space parameters \(\{m_0, \ldots, m_L\} \in \mathbb{N}^{L+1}\), and define the multilevel PCE as
where \(V_m\) denotes the polynomial space associated to parameter \(m\), e.g., the maximum degree in each dimension of the polynomial space.
To implement this using multichaos
, we need to specify the rates for convergence and cost of the underlying numerical solver, as well as polynomial approximability and dimensionality of the sequence of polynomial spaces. Mathematically, we assume there exist \(\beta, \gamma, \alpha, \sigma > 0\) such that
- \(\|Q - Q_n\|_{L^2} \lesssim n^{-\beta}\)
- \(\text{Work}(Q_n) \lesssim n^{\gamma}\)
- \(\inf_{v \in V_m} \|Q - v\|_{L^2} \lesssim m^{-\alpha}\)
- \(\text{dim}(V_m) \lesssim m^{\sigma}\)
In our example, using central finite differences as underyling solver, we have convergence rate \(\beta = 1\) and work rate \(\gamma = 1\). Using total degree polynomial spaces, we have approximability rate \(\alpha = 3\) and dimensionality rate \(\sigma = 2\). We need to pack these rates into a dictionary:
Also, we need to pass the mapping \(n \mapsto Q_n\) as an input to the MultiLevelPCE
class, which could be done by wrapping the previously defined response
function, where solve_bvp
is called with a specific \(n \in \mathbb{N}\):
def get_n_response(n: int) -> Callable:
def response(omega: np.ndarray) -> float:
# Solve the boundary-value problem
u = solve_bvp(omega, n=n)
# Compute the QoI
q = np.trapz(u, dx=1/n)
return q
return response
Now, we can create a MultiLevelPCE
:
from multichaos.multi_level import MultiLevelPCE
ml_pce = MultiLevelPCE(
response=get_n_response,
dist=dist,
index_set_type="TD",
rates=rates,
tol=tol,
)
The parameter tol
represents a tolerance \(\epsilon > 0\) for the desired \(L^2\) error, ensuring that
holds. Finally, we can run the compute_coefficients
method to compute the multilevel PCE coefficients:
Complexity analysis¶
According to theory, the computational costs for the (single-level) PCE to reach an error tolerance \(\epsilon > 0\), behave asymptotically as
On the other hand, using a multilevel PCE \(\hat{Q}\),
where \(\lambda = \max \left(\gamma / \beta,\, \sigma / \alpha\right)\) and
To visualize this, we compute single-level PCEs \(\Pi_{V_m} Q_n\) for diferent values of discretization \(n\) and polynomial space parameters \(m\). Also, we compute several multilevel PCEs \(\hat{Q}\) for different values of the tolerance \(\epsilon > 0\). The following figures show the \(L^2\) error versus the costs (here, time) for each PCE, single- and multilevel, respectively.

Each single-level PCE is represented by a gray dot, and the lower envelope (blue curve) of them is considered as the single-level complexity curve. One can clearly observe that the computed rates fit the theoretical rates, and the multilevel PCEs are more efficient than standard PCEs.