Example #1
0
def solve_lyap_lrcf(A, E, B, trans=False, options=None,
                    default_sparse_solver_backend=_DEFAULT_LYAP_LRCF_SPARSE_SOLVER_BACKEND,
                    default_dense_solver_backend=_DEFAULT_LYAP_LRCF_DENSE_SOLVER_BACKEND):
    """Compute an approximate low-rank solution of a Lyapunov equation.

    Returns a low-rank Cholesky factor :math:`Z` such that :math:`Z Z^T`
    approximates the solution :math:`X` of a (generalized)
    continuous-time algebraic Lyapunov equation:

    - if trans is `False` and E is `None`:

      .. math::
         A X + X A^T + B B^T = 0,

    - if trans is `False` and E is an |Operator|:

      .. math::
          A X E^T + E X A^T + B B^T = 0,

    - if trans is `True` and E is `None`:

      .. math::
          A^T X + X A + B^T B = 0,

    - if trans is `True` and E is an |Operator|:

      .. math::
          A^T X E + E^T X A + B^T B = 0.

    We assume A and E are real |Operators|, E is invertible, and all the
    eigenvalues of (A, E) all lie in the open left half-plane.
    Operator B needs to be given as a |VectorArray| from `A.source`, and
    for large-scale problems, we assume `len(B)` is small.

    If the solver is not specified using the options argument, a solver
    backend is chosen based on availability in the following order:

    - for sparse problems (minimum size specified by
      :func:`mat_eqn_sparse_min_size`)

      1. `pymess` (see :func:`pymor.bindings.pymess.solve_lyap_lrcf`),
      2. `lradi` (see :func:`pymor.algorithms.lradi.solve_lyap_lrcf`),

    - for dense problems (smaller than :func:`mat_eqn_sparse_min_size`)

      1. `pymess` (see :func:`pymor.bindings.pymess.solve_lyap_lrcf`),
      2. `slycot` (see :func:`pymor.bindings.slycot.solve_lyap_lrcf`),
      3. `scipy` (see :func:`pymor.bindings.scipy.solve_lyap_lrcf`).

    Parameters
    ----------
    A
        The |Operator| A.
    E
        The |Operator| E or `None`.
    B
        The operator B as a |VectorArray| from `A.source`.
    trans
        Whether the first |Operator| in the Lyapunov equation is
        transposed.
    options
        The solver options to use.
        See:

        - :func:`pymor.algorithms.lradi.lyap_lrcf_solver_options`,
        - :func:`pymor.bindings.scipy.lyap_lrcf_solver_options`,
        - :func:`pymor.bindings.slycot.lyap_lrcf_solver_options`,
        - :func:`pymor.bindings.pymess.lyap_lrcf_solver_options`.

    default_sparse_solver_backend
        Default sparse solver backend to use (pymess, lradi).
    default_dense_solver_backend
        Default dense solver backend to use (pymess, slycot, scipy).

    Returns
    -------
    Z
        Low-rank Cholesky factor of the Lyapunov equation solution,
        |VectorArray| from `A.source`.
    """

    _solve_lyap_lrcf_check_args(A, E, B, trans)
    if options:
        solver = options if isinstance(options, str) else options['type']
        backend = solver.split('_')[0]
    else:
        if A.source.dim >= mat_eqn_sparse_min_size():
            backend = default_sparse_solver_backend
        else:
            backend = default_dense_solver_backend
    if backend == 'scipy':
        from pymor.bindings.scipy import solve_lyap_lrcf as solve_lyap_impl
    elif backend == 'slycot':
        from pymor.bindings.slycot import solve_lyap_lrcf as solve_lyap_impl
    elif backend == 'pymess':
        from pymor.bindings.pymess import solve_lyap_lrcf as solve_lyap_impl
    elif backend == 'lradi':
        from pymor.algorithms.lradi import solve_lyap_lrcf as solve_lyap_impl
    else:
        raise ValueError(f'Unknown solver backend ({backend}).')
    return solve_lyap_impl(A, E, B, trans=trans, options=options)
Example #2
0
def solve_lyap_lrcf(
        A,
        E,
        B,
        trans=False,
        options=None,
        default_sparse_solver_backend=_DEFAULT_LYAP_LRCF_SPARSE_SOLVER_BACKEND,
        default_dense_solver_backend=_DEFAULT_LYAP_LRCF_DENSE_SOLVER_BACKEND):
    """Compute an approximate low-rank solution of a Lyapunov equation.

    Returns a low-rank Cholesky factor :math:`Z` such that :math:`Z Z^T`
    approximates the solution :math:`X` of a (generalized)
    continuous-time algebraic Lyapunov equation:

    - if trans is `False` and E is `None`:

      .. math::
         A X + X A^T + B B^T = 0,

    - if trans is `False` and E is an |Operator|:

      .. math::
          A X E^T + E X A^T + B B^T = 0,

    - if trans is `True` and E is `None`:

      .. math::
          A^T X + X A + B^T B = 0,

    - if trans is `True` and E is an |Operator|:

      .. math::
          A^T X E + E^T X A + B^T B = 0.

    We assume A and E are real |Operators|, E is invertible, and all the
    eigenvalues of (A, E) all lie in the open left half-plane.
    Operator B needs to be given as a |VectorArray| from `A.source`, and
    for large-scale problems, we assume `len(B)` is small.

    If the solver is not specified using the options argument, a solver
    backend is chosen based on availability in the following order:

    - for sparse problems (minimum size specified by
      :func:`mat_eqn_sparse_min_size`)

      1. `pymess` (see :func:`pymor.bindings.pymess.solve_lyap_lrcf`),
      2. `lradi` (see :func:`pymor.algorithms.lradi.solve_lyap_lrcf`),

    - for dense problems (smaller than :func:`mat_eqn_sparse_min_size`)

      1. `pymess` (see :func:`pymor.bindings.pymess.solve_lyap_lrcf`),
      2. `slycot` (see :func:`pymor.bindings.slycot.solve_lyap_lrcf`),
      3. `scipy` (see :func:`pymor.bindings.scipy.solve_lyap_lrcf`).

    Parameters
    ----------
    A
        The |Operator| A.
    E
        The |Operator| E or `None`.
    B
        The operator B as a |VectorArray| from `A.source`.
    trans
        Whether the first |Operator| in the Lyapunov equation is
        transposed.
    options
        The solver options to use.
        See:

        - :func:`pymor.algorithms.lradi.lyap_lrcf_solver_options`,
        - :func:`pymor.bindings.scipy.lyap_lrcf_solver_options`,
        - :func:`pymor.bindings.slycot.lyap_lrcf_solver_options`,
        - :func:`pymor.bindings.pymess.lyap_lrcf_solver_options`.

    default_sparse_solver_backend
        Default sparse solver backend to use (pymess, lradi).
    default_dense_solver_backend
        Default dense solver backend to use (pymess, slycot, scipy).

    Returns
    -------
    Z
        Low-rank Cholesky factor of the Lyapunov equation solution,
        |VectorArray| from `A.source`.
    """

    _solve_lyap_lrcf_check_args(A, E, B, trans)
    if options:
        solver = options if isinstance(options, str) else options['type']
        backend = solver.split('_')[0]
    else:
        if A.source.dim >= mat_eqn_sparse_min_size():
            backend = default_sparse_solver_backend
        else:
            backend = default_dense_solver_backend
    if backend == 'scipy':
        from pymor.bindings.scipy import solve_lyap_lrcf as solve_lyap_impl
    elif backend == 'slycot':
        from pymor.bindings.slycot import solve_lyap_lrcf as solve_lyap_impl
    elif backend == 'pymess':
        from pymor.bindings.pymess import solve_lyap_lrcf as solve_lyap_impl
    elif backend == 'lradi':
        from pymor.algorithms.lradi import solve_lyap_lrcf as solve_lyap_impl
    else:
        raise ValueError(f'Unknown solver backend ({backend}).')
    return solve_lyap_impl(A, E, B, trans=trans, options=options)
Example #3
0
def solve_lyap_dense(A, E, B, trans=False, options=None,
                     default_solver_backend=_DEFAULT_LYAP_DENSE_SOLVER_BACKEND):
    """Compute the solution of a Lyapunov equation.

    Returns the solution :math:`X` of a (generalized) continuous-time
    algebraic Lyapunov equation:

    - if trans is `False` and E is `None`:

      .. math::
          A X + X A^T + B B^T = 0,

    - if trans is `False` and E is an |Operator|:

      .. math::
          A X E^T + E X A^T + B B^T = 0,

    - if trans is `True` and E is `None`:

      .. math::
          A^T X + X A + B^T B = 0,

    - if trans is `True` and E is an |Operator|:

      .. math::
          A^T X E + E^T X A + B^T B = 0.

    We assume A and E are real |NumPy arrays|, E is invertible, and that
    no two eigenvalues of (A, E) sum to zero (i.e., there exists a
    unique solution X).

    If the solver is not specified using the options argument, a solver
    backend is chosen based on availability in the following order:

    1. `pymess` (see :func:`pymor.bindings.pymess.solve_lyap_dense`)
    2. `slycot` (see :func:`pymor.bindings.slycot.solve_lyap_dense`)
    3. `scipy` (see :func:`pymor.bindings.scipy.solve_lyap_dense`)

    Parameters
    ----------
    A
        The operator A as a 2D |NumPy array|.
    E
        The operator E as a 2D |NumPy array| or `None`.
    B
        The operator B as a 2D |NumPy array|.
    trans
        Whether the first operator in the Lyapunov equation is
        transposed.
    options
        The solver options to use.
        See:

        - :func:`pymor.bindings.scipy.lyap_dense_solver_options`,
        - :func:`pymor.bindings.slycot.lyap_dense_solver_options`,
        - :func:`pymor.bindings.pymess.lyap_dense_solver_options`.

    default_solver_backend
        Default solver backend to use (pymess, slycot, scipy).

    Returns
    -------
    X
        Lyapunov equation solution as a |NumPy array|.
    """

    _solve_lyap_dense_check_args(A, E, B, trans)
    if options:
        solver = options if isinstance(options, str) else options['type']
        backend = solver.split('_')[0]
    else:
        backend = default_solver_backend
    if backend == 'scipy':
        from pymor.bindings.scipy import solve_lyap_dense as solve_lyap_impl
    elif backend == 'slycot':
        from pymor.bindings.slycot import solve_lyap_dense as solve_lyap_impl
    elif backend == 'pymess':
        from pymor.bindings.pymess import solve_lyap_dense as solve_lyap_impl
    else:
        raise ValueError(f'Unknown solver backend ({backend}).')
    return solve_lyap_impl(A, E, B, trans, options=options)
Example #4
0
def solve_lyap_dense(
        A,
        E,
        B,
        trans=False,
        options=None,
        default_solver_backend=_DEFAULT_LYAP_DENSE_SOLVER_BACKEND):
    """Compute the solution of a Lyapunov equation.

    Returns the solution :math:`X` of a (generalized) continuous-time
    algebraic Lyapunov equation:

    - if trans is `False` and E is `None`:

      .. math::
          A X + X A^T + B B^T = 0,

    - if trans is `False` and E is an |Operator|:

      .. math::
          A X E^T + E X A^T + B B^T = 0,

    - if trans is `True` and E is `None`:

      .. math::
          A^T X + X A + B^T B = 0,

    - if trans is `True` and E is an |Operator|:

      .. math::
          A^T X E + E^T X A + B^T B = 0.

    We assume A and E are real |NumPy arrays|, E is invertible, and that
    no two eigenvalues of (A, E) sum to zero (i.e., there exists a
    unique solution X).

    If the solver is not specified using the options argument, a solver
    backend is chosen based on availability in the following order:

    1. `pymess` (see :func:`pymor.bindings.pymess.solve_lyap_dense`)
    2. `slycot` (see :func:`pymor.bindings.slycot.solve_lyap_dense`)
    3. `scipy` (see :func:`pymor.bindings.scipy.solve_lyap_dense`)

    Parameters
    ----------
    A
        The operator A as a 2D |NumPy array|.
    E
        The operator E as a 2D |NumPy array| or `None`.
    B
        The operator B as a 2D |NumPy array|.
    trans
        Whether the first operator in the Lyapunov equation is
        transposed.
    options
        The solver options to use.
        See:

        - :func:`pymor.bindings.scipy.lyap_dense_solver_options`,
        - :func:`pymor.bindings.slycot.lyap_dense_solver_options`,
        - :func:`pymor.bindings.pymess.lyap_dense_solver_options`.

    default_solver_backend
        Default solver backend to use (pymess, slycot, scipy).

    Returns
    -------
    X
        Lyapunov equation solution as a |NumPy array|.
    """

    _solve_lyap_dense_check_args(A, E, B, trans)
    if options:
        solver = options if isinstance(options, str) else options['type']
        backend = solver.split('_')[0]
    else:
        backend = default_solver_backend
    if backend == 'scipy':
        from pymor.bindings.scipy import solve_lyap_dense as solve_lyap_impl
    elif backend == 'slycot':
        from pymor.bindings.slycot import solve_lyap_dense as solve_lyap_impl
    elif backend == 'pymess':
        from pymor.bindings.pymess import solve_lyap_dense as solve_lyap_impl
    else:
        raise ValueError(f'Unknown solver backend ({backend}).')
    return solve_lyap_impl(A, E, B, trans, options=options)