Skip to content

qttools.boundary_conditions.system_reduction#

[docs] module qttools.boundary_conditions.system_reduction

# Copyright (c) 2024-2026 ETH Zurich and the authors of the qttools package.

from abc import ABC, abstractmethod

from qttools import NDArray


class SystemReducer(ABC):
    """Interface for reducing the boundary system to a smaller system.
    The boundary system can exhibit sparsity or symmetries, which can be
    exploited to reduce the size of the system.

    """

    @abstractmethod
    def contract_system(
        self,
        boundary_system: tuple[NDArray, ...],
    ) -> tuple[NDArray, ...]:
        """Contract the boundary system to a reduced system.
        This method should identify and remove redundancies in the boundary system,
        resulting in a smaller system that is easier to solve.

        Parameters
        ----------
        boundary_system : tuple[NDArray, ...]
            The full boundary system.

        Returns
        -------
        reduced_system : tuple[NDArray, ...]
            The reduced boundary system.

        """
        ...

    @abstractmethod
    def expand_solution(
        self,
        boundary_system: tuple[NDArray, ...],
        reduced_system: tuple[NDArray, ...],
        reduced_solution: NDArray | tuple[NDArray, ...],
    ) -> NDArray | tuple[NDArray, ...]:
        """Expand the solution from the reduced system to the full system.
        The method should be called after `contract_system` and solving the system.
        It should take the solution of the reduced system and map it back to the full system,
        filling in any missing values as necessary.

        Parameters
        ----------
        boundary_system : tuple[NDArray, ...]
            The full boundary system.
        reduced_system : tuple[NDArray, ...]
            The reduced boundary system.
        reduced_solution : NDArray | tuple[NDArray, ...]
            The solution of the reduced system.

        Returns
        -------
        full_solution : NDArray | tuple[NDArray, ...]
            The solution of the full system.

        """
        ...

    @abstractmethod
    def expand_residuals(
        self,
        boundary_system: tuple[NDArray, ...],
        reduced_system: tuple[NDArray, ...],
        rel_residuals: NDArray,
        abs_residuals: NDArray,
    ) -> tuple[NDArray, NDArray]:
        """Expand the residuals from the reduced system to the full system.
        The method should be called after `contract_system` and solving the system.
        It should take the residuals of the reduced system and map them back to the full system,
        filling in any missing values as necessary.

        Parameters
        ----------
        boundary_system : tuple[NDArray, ...]
            The full boundary system.
        reduced_system : tuple[NDArray, ...]
            The reduced boundary system.
        rel_residuals : NDArray
            The relative residuals of the reduced system.
        abs_residuals : NDArray
            The absolute residuals of the reduced system.

        Returns
        -------
        full_rel_residuals : NDArray
            The relative residuals of the full system.
        full_abs_residuals : NDArray
            The absolute residuals of the full system.

        """
        ...


class IdentityReducer(SystemReducer):
    """A system reducer that does not perform any reduction. It simply returns the input as output.
    This can be used as a default reducer when no reduction is desired."""

    def contract_system(
        self,
        boundary_system: tuple[NDArray, ...],
    ) -> tuple[NDArray, ...]:
        """Do not contract the boundary system, return it as is.
        The retured system alias the input system.

        Parameters
        ----------
        boundary_system : tuple[NDArray, ...]
            The full boundary system.

        Returns
        -------
        reduced_system : tuple[NDArray, ...]
            The reduced boundary system.

        """
        return boundary_system

    def expand_solution(
        self,
        boundary_system: tuple[NDArray, ...],
        reduced_system: tuple[NDArray, ...],
        reduced_solution: NDArray | tuple[NDArray, ...],
    ) -> NDArray | tuple[NDArray, ...]:
        """Do not expand the solution, return it as is.
        The returned solution alias the input solution.

        Parameters
        ----------
        boundary_system : tuple[NDArray, ...]
            The full boundary system.
        reduced_system : tuple[NDArray, ...]
            The reduced boundary system.
        reduced_solution : NDArray | tuple[NDArray, ...]
            The solution of the reduced system.

        Returns
        -------
        full_solution : NDArray | tuple[NDArray, ...]
            The solution of the full system.

        """
        return reduced_solution

    def expand_residuals(
        self,
        boundary_system: tuple[NDArray, ...],
        reduced_system: tuple[NDArray, ...],
        rel_residuals: NDArray,
        abs_residuals: NDArray,
    ) -> tuple[NDArray, NDArray]:
        """Do not expand the residuals, return them as is.
        The returned residuals alias the input residuals.

        Parameters
        ----------
        boundary_system : tuple[NDArray, ...]
            The full boundary system.
        reduced_system : tuple[NDArray, ...]
            The reduced boundary system.
        rel_residuals : NDArray
            The relative residuals of the reduced system.
        abs_residuals : NDArray
            The absolute residuals of the reduced system.

        Returns
        -------
        full_rel_residuals : NDArray
            The relative residuals of the full system.
        full_abs_residuals : NDArray
            The absolute residuals of the full system.

        """
        return rel_residuals, abs_residuals