# Source code for pymor.reductors.basic

```# This file is part of the pyMOR project (http://www.pymor.org).
# Copyright 2013-2016 pyMOR developers and contributors. All rights reserved.
# License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

from __future__ import absolute_import, division, print_function

import numpy as np

from pymor.core.interfaces import BasicInterface
from pymor.vectorarrays.numpy import NumpyVectorArray

[docs]class GenericRBReconstructor(BasicInterface):
"""Simple reconstructor forming linear combinations with a reduced basis."""

def __init__(self, RB):
self.RB = RB.copy()

[docs]    def reconstruct(self, U):
"""Reconstruct high-dimensional vector from reduced vector `U`."""
assert isinstance(U, NumpyVectorArray)
return self.RB.lincomb(U.data)

[docs]    def restricted_to_subbasis(self, dim):
"""See :meth:`~pymor.operators.numpy.NumpyMatrixOperator.projected_to_subbasis`."""
assert dim <= len(self.RB)
return GenericRBReconstructor(self.RB.copy(ind=range(dim)))

[docs]def reduce_generic_rb(discretization, RB, vector_product=None, disable_caching=True, extends=None):
"""Generic reduced basis reductor.

Replaces each |Operator| of the given |Discretization| with the Galerkin
projection onto the span of the given reduced basis.

Parameters
----------
discretization
The |Discretization| which is to be reduced.
RB
|VectorArray| containing the reduced basis on which to project.
vector_product
Inner product for the projection of vector-like |Operators|.
(A typical vector-like operator would be the `initial_data`
|Operator| of an |InstationaryDiscretization| holding
the initial data of a Cauchy problem.)
disable_caching
If `True`, caching of solutions is disabled for the reduced |Discretization|.
extends
Set by :meth:`~pymor.algorithms.greedy.greedy` to the result of the
last reduction in case the basis extension was `hierarchic` (ignored).

Returns
-------
rd
The reduced |Discretization|.
rc
The :class:`reconstructor <GenericRBReconstructor>` providing a
`reconstruct(U)` method which reconstructs high-dimensional solutions
from solutions `U` of the reduced |Discretization|.
reduction_data
Additional data produced by the reduction process (empty).
"""
assert extends is None or len(extends) == 3

if RB is None:
RB = discretization.solution_space.empty()

projected_operators = {k: op.projected(range_basis=RB, source_basis=RB, product=None) if op else None
for k, op in discretization.operators.iteritems()}
projected_functionals = {k: f.projected(range_basis=None, source_basis=RB, product=None) if f else None
for k, f in discretization.functionals.iteritems()}
projected_vector_operators = {k: (op.projected(range_basis=RB, source_basis=None, product=vector_product) if op
else None)
for k, op in discretization.vector_operators.iteritems()}

if discretization.products is not None:
projected_products = {k: p.projected(range_basis=RB, source_basis=RB)
for k, p in discretization.products.iteritems()}
else:
projected_products = None

cache_region = None if disable_caching else discretization.caching

rd = discretization.with_(operators=projected_operators, functionals=projected_functionals,
vector_operators=projected_vector_operators,
products=projected_products, visualizer=None, estimator=None,
cache_region=cache_region, name=discretization.name + '_reduced')
rd.disable_logging()
rc = GenericRBReconstructor(RB)

return rd, rc, {}

[docs]class SubbasisReconstructor(BasicInterface):
"""Returned by :meth:`reduce_to_subbasis`."""

def __init__(self, dim, dim_subbasis, old_recontructor=None):
self.dim = dim
self.dim_subbasis = dim_subbasis
self.old_recontructor = old_recontructor

[docs]    def reconstruct(self, U):
"""Reconstruct high-dimensional vector from reduced vector `U`."""
assert isinstance(U, NumpyVectorArray)
UU = np.zeros((len(U), self.dim))
UU[:, :self.dim_subbasis] = U.data
UU = NumpyVectorArray(UU, copy=False)
if self.old_recontructor:
return self.old_recontructor.reconstruct(UU)
else:
return UU

[docs]def reduce_to_subbasis(discretization, dim, reconstructor=None):
"""Further reduce a |Discretization| to the subbasis formed by the first `dim` basis vectors.

This is achieved by calling :meth:`~pymor.operators.numpy.NumpyMatrixOperator.projected_to_subbasis`
for each operator of the given |Discretization|. Additionally, if a reconstructor
for the |Discretization| is provided, its :meth:`restricted_to_subbasis` method is also
called to obtain a reconstructor for the further reduced |Discretization|. Otherwise
:class:`SubbasisReconstructor` is used (which will be less efficient).

Parameters
----------
discretization
The |Discretization| to further reduce.
dim
The dimension of the subbasis.
reconstructor
Reconstructor for `discretization` or `None`.

Returns
-------
rd
The further reduced |Discretization|.
rc
Reconstructor for `rd`.
"""

projected_operators = {k: op.projected_to_subbasis(dim_range=dim, dim_source=dim) if op is not None else None
for k, op in discretization.operators.iteritems()}
projected_functionals = {k: f.projected_to_subbasis(dim_range=None, dim_source=dim) if f is not None else None
for k, f in discretization.functionals.iteritems()}
projected_vector_operators = {k: op.projected_to_subbasis(dim_range=dim, dim_source=None) if op else None
for k, op in discretization.vector_operators.iteritems()}

if discretization.products is not None:
projected_products = {k: op.projected_to_subbasis(dim_range=dim, dim_source=dim)
for k, op in discretization.products.iteritems()}
else:
projected_products = None

if hasattr(discretization, 'estimator') and hasattr(discretization.estimator, 'restricted_to_subbasis'):
estimator = discretization.estimator.restricted_to_subbasis(dim, discretization=discretization)
elif hasattr(discretization, 'estimate'):
# noinspection PyShadowingNames
class FakeEstimator(object):
rd = discretization
rc = SubbasisReconstructor(discretization.solution_space.dim, dim)

def estimate(self, U, mu=None, discretization=None):
return self.rd.estimate(self.rc.reconstruct(U), mu=mu)
estimator = FakeEstimator()
else:
estimator = None

rd = discretization.with_(operators=projected_operators, functionals=projected_functionals,
vector_operators=projected_vector_operators,
products=projected_products, visualizer=None, estimator=estimator,
name=discretization.name + '_reduced_to_subbasis')
rd.disable_logging()

if reconstructor is not None and hasattr(reconstructor, 'restricted_to_subbasis'):
rc = reconstructor.restricted_to_subbasis(dim)
else:
rc = SubbasisReconstructor(discretization.solution_space.dim, dim,
old_recontructor=reconstructor)

return rd, rc, {}
```