Пример #1
0
def gen_BandMat_simple(size):
    """Generates a random BandMat."""
    l = random.choice([0, 1, randint(0, 10)])
    u = random.choice([0, 1, randint(0, 10)])
    data = randn(l + u + 1, size)
    transposed = rand_bool()
    return bm.BandMat(l, u, data, transposed=transposed)
Пример #2
0
def prepare_mats(refl, alpha=1e3):
    """
    Does some prep to produce matrices for the TDMA
    """
    y = refl
    Iobs = y > 0
    nT, ys, xs = y.shape
    # Create mats
    AC, BC, CC, DC = [  np.zeros([nT-1, ys, xs], dtype=np.float32),
                        np.zeros([nT, ys, xs], dtype=np.float32),
                        np.zeros([nT-1, ys, xs],  dtype=np.float32),
                        np.zeros([nT, ys, xs],  dtype=np.float32)]
    # Create Diagonals matrices
    # for ease just use bandmat for this for now
    # Form diagonals
    I = np.eye(nT)  #np.diag (np.ones(nx))
    D = (I - np.roll(I, -1)).T
    #D = D.T.dot(D)
    D1A = np.zeros((nT, 2))
    D1A[1:, 0] = np.diag(D, 1)
    D1A[:, 1] = np.diag(D, 0)
    # convert to banded matrices
    D = bm.BandMat(0, 1, D1A.T, transposed=False)
    D2 = bm.dot_mm(D.T, D)
    a = alpha * D2.data[2][:-1]
    b = alpha * D2.data[1]
    c = alpha * D2.data[0][1:]
    # add these
    AC[:]=a[:, None, None]
    BC[:]=b[:, None, None]+ Iobs
    CC[:]=c[:, None, None]
    DC[:]=y
    return AC, BC, CC, DC
Пример #3
0
def smooth(a, Phat, N, lambda_1, lambda_2):
    """
    a: (N,) number of measurements at that timestep
    Phat: (N, 3) sum of measurements at that timestep
    N: num time steps
    lambda_1, lambda_2: regularization parameters

    solves the optimization problem (over P \in R^{Tx3}):
    minimize ||diag(a)*P-Phat||^2 + lambda_1/N*||D_2*P||^2 + lambda_2/N*||D_3*P||^2

    returns:
        - P: (N, 3) matrix with full trajectory
    """
    # A in Banded Matrix form
    A = bm.diag(1. * a)

    # D_2 and D_3 in Banded Matrix form transposed
    D_2_bm_T = bm.BandMat(
        1, 1,
        np.hstack([
            np.zeros((3, 1)),
            np.repeat([[1.], [-2.], [1.]], N - 2, axis=1),
            np.zeros((3, 1))
        ]))
    D_3_bm_T = bm.BandMat(
        2, 2,
        np.hstack([
            np.zeros((5, 2)),
            np.repeat([[-1.], [2.], [0.], [-2.], [1.]], N - 4, axis=1),
            np.zeros((5, 2))
        ]))

    # XP=B normal equations
    X = bm.dot_mm(A, A) + lambda_1 / N * bm.dot_mm(
        D_2_bm_T, D_2_bm_T.T) + lambda_2 / N * bm.dot_mm(D_3_bm_T, D_3_bm_T.T)
    l_and_u = (X.l, X.u)  # lower and upper band bounds
    B = np.hstack([
        np.expand_dims(bm.dot_mv(A, Phat[:, 0]), -1),
        np.expand_dims(bm.dot_mv(A, Phat[:, 1]), -1),
        np.expand_dims(bm.dot_mv(A, Phat[:, 2]), -1)
    ])

    # solve normal equations
    P = solve_banded(l_and_u, X.data, B)

    return P
Пример #4
0
    def test__cholesky_banded(self, its=100):
        for it in range(its):
            size = random.choice([0, 1, randint(0, 10), randint(0, 100)])
            if rand_bool():
                mat_bm = gen_pos_def_BandMat(size, transposed=False)
            else:
                mat_bm = gen_symmetric_BandMat(size, transposed=False)
                # make it a bit more likely to be pos def
                bm.diag(mat_bm)[:] = np.abs(bm.diag(mat_bm)) + 0.1
            depth = mat_bm.l
            lower = rand_bool()
            if lower:
                mat_half_data = mat_bm.data[depth:]
            else:
                mat_half_data = mat_bm.data[:(depth + 1)]
            overwrite = rand_bool()

            mat_half_data_arg = mat_half_data.copy()
            try:
                chol_data = bla._cholesky_banded(mat_half_data_arg,
                                                 overwrite_ab=overwrite,
                                                 lower=lower)
            except la.LinAlgError as e:
                # First part of the message is e.g. "2-th leading minor".
                msgRe = (r'^' + re.escape(str(e)[:15]) +
                         r'.*not positive definite$')
                with self.assertRaisesRegexp(la.LinAlgError, msgRe):
                    sla.cholesky(mat_bm.full(), lower=lower)
            else:
                assert np.shape(chol_data) == (depth + 1, size)
                if lower:
                    chol_bm = bm.BandMat(depth, 0, chol_data)
                    mat_bm_again = bm.dot_mm(chol_bm, chol_bm.T)
                else:
                    chol_bm = bm.BandMat(0, depth, chol_data)
                    mat_bm_again = bm.dot_mm(chol_bm.T, chol_bm)
                assert_allclose(mat_bm_again.full(), mat_bm.full())

                if size > 0:
                    self.assertEqual(
                        np.may_share_memory(chol_data, mat_half_data_arg),
                        overwrite)

            if not overwrite:
                assert np.all(mat_half_data_arg == mat_half_data)
Пример #5
0
def gen_BandMat(size, l=None, u=None, transposed=None):
    """Generates a random BandMat."""
    if l is None:
        l = random.choice([0, 1, randint(0, 10)])
    if u is None:
        u = random.choice([0, 1, randint(0, 10)])
    data = randn(l + u + 1, size)
    if transposed is None:
        transposed = rand_bool()
    return bm.BandMat(l, u, data, transposed=transposed)
Пример #6
0
def make_D_matrix(nT):
    """
    a function to make a sparse D matrix
    """
    I = np.eye(nT)  #np.diag (np.ones(nx))
    D = (I - np.roll(I, -1)).T
    #D = D.T.dot(D)
    D1A = np.zeros((nT, 2))
    D1A[1:, 0] = np.diag(D, 1)
    D1A[:, 1] = np.diag(D, 0)
    # convert to banded matrices
    D = bm.BandMat(0, 1, D1A.T, transposed=False)
    return D
Пример #7
0
#!/usr/bin/python
"""A simple example of how the bandmat package may be used."""

# Copyright 2013, 2014, 2015, 2016, 2017, 2018 Matt Shannon

# This file is part of bandmat.
# See `License` for details of license and warranty.

import numpy as np

import bandmat as bm

a_bm = bm.BandMat(
    1, 1,
    np.array([
        [0.0, 0.2, 0.3, 0.4, 0.5],
        [1.0, 0.9, 1.1, 0.8, 1.3],
        [0.3, 0.1, 0.5, 0.6, 0.0],
    ]))

b_bm = bm.BandMat(
    1, 0, np.array([
        [1.0, 0.9, 1.1, 0.8, 1.3],
        [0.3, 0.1, 0.5, 0.6, 0.0],
    ]))

c_bm = bm.dot_mm(a_bm.T, b_bm)

d_bm = a_bm + b_bm

a_full = a_bm.full()
Пример #8
0
def solve_band(refl, solve_edge=True, W=None, alpha=1000, unc=False, drop=True):
    """
    test run function
    """
    Iobs = (refl>0)
    nObs = (Iobs).sum(axis=0)
    # scale alpha
    alpha = 1
    alpha = alpha * np.nanmean(nObs)
    alpha = np.clip(alpha, 20, 250)
    if solve_edge:
        T = .6 * alpha
        nT, ys, xs = refl.shape
        # make D matrix
        I = np.eye(nT)  #np.diag (np.ones(nx))
        D = (I - np.roll(I, -1)).T
        #D = D.T.dot(D)
        D1A = np.zeros((nT, 2))
        D1A[1:, 0] = np.diag(D, 1)
        D1A[:, 1] = np.diag(D, 0)
        # convert to banded matrices
        _D = bm.BandMat(0, 1, D1A.T, transposed=False)
        # create mats
        A, B, C, D = prepare_mats(refl, alpha=alpha)
        # Initial run with no smoothing
        X = TDMA_MAT(A, B, C, D)
        W0 = np.ones_like(X)*100
        WW = np.ones_like(X)
        X0 = np.zeros_like(D)
        CONV = np.zeros((ys, xs)).astype(np.bool)
        Nits =  np.zeros((ys, xs), dtype=np.int)
        for i in range(5):
            # calculate weights
            order_n = 1
            #dx = np.diff(X, axis=0, n=order_n)* alpha**2
            dx = np.gradient(X, axis=0) * alpha**2
            # enforce direction constraint
            if drop != None:
                if drop:
                    dx[dx>0]=0
                else:
                    dx[dx<=0]=0
            # eg frst 30 days and last 30 days
            _w = np.exp(-dx**2 / T)
            """
            Scaling from CERC
            """
            y,x=30, 57
            wScale = nObs / np.sum(_w, axis=0)
            _w = _w * wScale
            _w = np.clip(_w, 0., 1)
            np.place(_w, np.isnan(_w), 1)
            WW[:]=_w
            """
            Update the regularisation matrix
            with the weights

            -- This involves a dot product
            with a diag eg D.T W D
                so i don't how to do this atm

            This is the slowest so if this can be done fast much better
            """
            for y in range(ys):
                for x in range(xs):
                    if not CONV[y,x]:
                        # no convergence keep going
                        n = alpha * bm.dot_mm(_D.T, _D, diag=WW[:, y, x].astype(np.float))
                        a = n.data[2][:-1]
                        b = n.data[1]  + Iobs[:, y, x]
                        c = n.data[0][1:]
                        # update matrices
                        A[:, y, x]=a
                        B[:, y, x]=b
                        C[:, y, x]=c
                        Nits[y,x]+=1
            """
            Run again with new weights
            """
            X = TDMA_MAT(A, B, C, D)
            """
            assess convergence
            -eg are the weights still changing
            """
            cow = np.sum(np.abs((WW - W0) / W0), axis=0)+ 1e-6
            CONV[cow<1e-2]=True
            MINITER=3
            if i< MINITER:
                CONV[:]=False
            CONV[WW.min(axis=0)<0.1]=True
            W0 = WW
            X0 = X
        """
        Want to check steps and re-inforce real steps
        """
        W, keptEdges, Sch = refine_edges(WW, X, refl)
        """
        Resolve with refined edges
        """
        for y in range(ys):
            for x in range(xs):
                    n = alpha * bm.dot_mm(_D.T, _D, diag=W[:, y, x].astype(np.float))
                    a = n.data[2][:-1]
                    b = n.data[1]  + Iobs[:, y, x]
                    c = n.data[0][1:]
                    # update matrices
                    A[:, y, x]=a
                    B[:, y, x]=b
                    C[:, y, x]=c
                    Nits[y,x]+=1
        """
        Run again with the refined weights
        """
        #y,x=43, 62
        if unc:
            X = TDMA_MAT(A, B, C, D)
            DD = np.copy(D).astype(np.float32)
            Inv = np.zeros_like(X)
            # only need the middle month tbh
            for t in range(20, nT-20):
                DD[:]=0
                DD[t]=1
                Inv[t]=TDMA_MAT(A, B, C, DD)[t]
            return X, Inv, W, CONV, Nits, Sch
        else:
            X = TDMA_MAT(A, B, C, D)
            return X, W, CONV, Nits, Sch
    else:
        """
        Edge has been provided so use that
        """
        Iobs = (refl>0)
        nObs = (Iobs).sum(axis=0)
        nT, ys, xs = refl.shape
        # make D matrix
        I = np.eye(nT)  #np.diag (np.ones(nx))
        D = (I - np.roll(I, -1)).T
        #D = D.T.dot(D)
        D1A = np.zeros((nT, 2))
        D1A[1:, 0] = np.diag(D, 1)
        D1A[:, 1] = np.diag(D, 0)
        # convert to banded matrices
        _D = bm.BandMat(0, 1, D1A.T, transposed=False)
        # create mats
        A, B, C, D = prepare_mats(refl, alpha=alpha)
        # add the weights matrix
        for y in range(ys):
            for x in range(xs):
                n = alpha * bm.dot_mm(_D.T, _D, diag=W[:, y, x].astype(np.float))
                a = n.data[2][:-1]
                b = n.data[1]  + Iobs[:, y, x]
                c = n.data[0][1:]
                # update matrices
                A[:, y, x]=a
                B[:, y, x]=b
                C[:, y, x]=c
        """
        Run again with the refined weights
        """
        X = TDMA_MAT(A, B, C, D)
        return X, W