Exemple #1
0
    def test_mb03rd_default(self):
        # regression: mb03rd was failing with no third arg (X) supplied
        A = np.array([[6, -1, -7, -2, 2], [-3, 4, 2, -7, 6],
                      [-6, -9, -3, -1, 10], [-2, -4, 1, 5, 7],
                      [-7, -5, -6, 6, 7]])

        Aschur, Tschur = schur(A)

        X = Tschur.copy()

        Ar, Xr, blsize, W = mb03rd(Aschur.shape[0],
                                   Aschur,
                                   X,
                                   'U',
                                   'N',
                                   pmax=1.0,
                                   tol=0.0)

        Ar2, Xr2, blsize2, W2 = mb03rd(Aschur.shape[0], Aschur)

        assert_allclose(Ar, Ar2)
        assert_allclose(Xr, Tschur.dot(Xr2))
Exemple #2
0
    def test_mb03rd(self):
        """ Test for Schur form reduction.

        RvP, 31 Jul 2019"""

        test1_A = np.array([[1., -1., 1., 2., 3., 1., 2., 3.],
                            [1., 1., 3., 4., 2., 3., 4., 2.],
                            [0., 0., 1., -1., 1., 5., 4., 1.],
                            [0., 0., 0., 1., -1., 3., 1., 2.],
                            [0., 0., 0., 1., 1., 2., 3., -1.],
                            [0., 0., 0., 0., 0., 1., 5., 1.],
                            [0., 0., 0., 0., 0., 0., 0.99999999, -0.99999999],
                            [0., 0., 0., 0., 0., 0., 0.99999999, 0.99999999]])
        test1_n = test1_A.shape[0]

        test1_Ar = np.array([
            [
                1.0000, -1.0000, -1.2247, -0.7071, -3.4186, 1.4577, 0.0000,
                0.0000
            ],
            [1.0000, 1.0000, 0.0000, 1.4142, -5.1390, 3.1637, 0.0000, 0.0000],
            [0.0000, 0.0000, 1.0000, -1.7321, -0.0016, 2.0701, 0.0000, 0.0000],
            [0.0000, 0.0000, 0.5774, 1.0000, 0.7516, 1.1379, 0.0000, 0.0000],
            [0.0000, 0.0000, 0.0000, 0.0000, 1.0000, -5.8606, 0.0000, 0.0000],
            [0.0000, 0.0000, 0.0000, 0.0000, 0.1706, 1.0000, 0.0000, 0.0000],
            [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 1.0000, -0.8850],
            [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 1.0000],
        ])

        test1_Xr = np.array(
            [[1.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.9045, 0.1957],
             [0.0000, 1.0000, 0.0000, 0.0000, 0.0000, 0.0000, -0.3015, 0.9755],
             [
                 0.0000, 0.0000, 0.8165, 0.0000, -0.5768, -0.0156, -0.3015,
                 0.0148
             ],
             [
                 0.0000, 0.0000, -0.4082, 0.7071, -0.5768, -0.0156, 0.0000,
                 -0.0534
             ],
             [
                 0.0000, 0.0000, -0.4082, -0.7071, -0.5768, -0.0156, 0.0000,
                 0.0801
             ],
             [0.0000, 0.0000, 0.0000, 0.0000, -0.0276, 0.9805, 0.0000, 0.0267],
             [0.0000, 0.0000, 0.0000, 0.0000, 0.0332, -0.0066, 0.0000, 0.0000],
             [0.0000, 0.0000, 0.0000, 0.0000, 0.0011, 0.1948, 0.0000, 0.0000]])

        test1_W = np.array([
            1 + 1j, 1 - 1j, 1 + 1j, 1 - 1j, 0.99999 + 0.99999j,
            0.99999 - 0.99999j, 1., 1.
        ])

        test1_pmax = 1e3
        test1_tol = 0.01
        # create schur form with scipy
        A, X = schur(test1_A)
        Ah, Xh = np.copy(A), np.copy(X)
        # on this basis, get the transform
        Ar, Xr, blsize, W = mb03rd(test1_n, A, X, 'U', 'S', test1_pmax,
                                   test1_tol)
        # ensure X and A are unchanged
        assert_allclose(A, Ah)
        assert_allclose(X, Xh)
        # compare to test case results
        assert_allclose(Ar, test1_Ar, atol=0.0001)
        assert_allclose(Xr, test1_Xr, atol=0.0001)
        assert_allclose(W, test1_W, atol=0.0001)

        # Test that the non sorting options do not throw errors and that Xr is
        # returned as None for jobx='N'
        for sort in ['N', 'C', 'B']:
            Ar, Xr, blsize, W = mb03rd(test1_n, A, X, 'N', sort, test1_pmax,
                                       test1_tol)
            assert Xr is None
Exemple #3
0
def _bdschur_condmax_search(aschur, tschur, condmax):
    """Block-diagonal Schur decomposition search up to condmax

    Iterates mb03rd with different pmax values until:
      - result is non-defective;
      - or condition number of similarity transform is unchanging despite large pmax;
      - or condition number of similarity transform is close to condmax.

    Parameters
    ----------
    aschur: (N, N) real ndarray
      Real Schur-form matrix
    tschur: (N, N) real ndarray
      Orthogonal transformation giving aschur from some initial matrix a
    condmax: float
      Maximum condition number of final transformation.  Must be >= 1.

    Returns
    -------
    amodal: (N, N) real ndarray
       block diagonal Schur form
    tmodal: (N, N) real ndarray
       similarity transformation give amodal from aschur
    blksizes: (M,) int ndarray
       Array of Schur block sizes
    eigvals: (N,) real or complex ndarray
       Eigenvalues of amodal (and a, etc.)

    Notes
    -----
    Outputs as for slycot.mb03rd

    aschur, tschur are as returned by scipy.linalg.schur.
    """
    try:
        from slycot import mb03rd
    except ImportError:
        raise ControlSlycot("can't find slycot module 'mb03rd'")

    # see notes on RuntimeError below
    pmaxlower = None

    # get lower bound; try condmax ** 0.5 first
    pmaxlower = condmax**0.5
    amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0],
                                               aschur,
                                               tschur,
                                               pmax=pmaxlower)
    if np.linalg.cond(tmodal) <= condmax:
        reslower = amodal, tmodal, blksizes, eigvals
    else:
        pmaxlower = 1.0
        amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0],
                                                   aschur,
                                                   tschur,
                                                   pmax=pmaxlower)
        cond = np.linalg.cond(tmodal)
        if cond > condmax:
            msg = 'minimum cond={} > condmax={}; try increasing condmax'.format(
                cond, condmax)
            raise RuntimeError(msg)

    pmax = pmaxlower

    # phase 1: search for upper bound on pmax
    for i in range(50):
        amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0],
                                                   aschur,
                                                   tschur,
                                                   pmax=pmax)
        cond = np.linalg.cond(tmodal)
        if cond < condmax:
            pmaxlower = pmax
            reslower = amodal, tmodal, blksizes, eigvals
        else:
            # upper bound found; go to phase 2
            pmaxupper = pmax
            break

        if _bdschur_defective(blksizes, eigvals):
            pmax *= 2
        else:
            return amodal, tmodal, blksizes, eigvals
    else:
        # no upper bound found; return current result
        return reslower

    # phase 2: bisection search
    for i in range(50):
        pmax = (pmaxlower * pmaxupper)**0.5
        amodal, tmodal, blksizes, eigvals = mb03rd(aschur.shape[0],
                                                   aschur,
                                                   tschur,
                                                   pmax=pmax)
        cond = np.linalg.cond(tmodal)

        if cond < condmax:
            if not _bdschur_defective(blksizes, eigvals):
                return amodal, tmodal, blksizes, eigvals
            pmaxlower = pmax
            reslower = amodal, tmodal, blksizes, eigvals
        else:
            pmaxupper = pmax

        if pmaxupper / pmaxlower < _PMAX_SEARCH_TOL:
            # hit search limit
            return reslower
    else:
        raise ValueError(
            'bisection failed to converge; pmaxlower={}, pmaxupper={}'.format(
                pmaxlower, pmaxupper))