Exemplo n.º 1
0
    def test_gram(self):
        """test construction of gram matrix"""

        tdt_1 = tdt.basis_decomposition(self.data, self.phi_1).transpose(cores=[self.d]).matricize()
        tdt_2 = tdt.basis_decomposition(self.data_2, self.phi_1).transpose(cores=[self.d]).matricize()
        gram = tdt.gram(self.data, self.data_2, self.phi_1)
        self.assertLess(np.sum(np.abs(tdt_1.T.dot(tdt_2) - gram)), self.tol)
Exemplo n.º 2
0
def construct_tdm(data, basis_list):
    """Construct transformed data matrices.

    Parameters
    ----------
    data: ndarray
        snapshot matrix
    basis_list: list of lists of lambda functions
        list of basis functions in every mode

    Returns
    -------
    psi_x: instance of TT class
        transformed data matrix corresponding to x
    psi_y: instance of TT class
        transformed data matrix corresponding to y
    """

    # extract snapshots for x and y
    x = data[:, :-1]
    y = data[:, 1:]

    # construct psi_x and psi_y
    start_time = utl.progress('Construct transformed data matrices', 0)
    psi_x = tdt.basis_decomposition(x, basis_list).transpose(cores=2).matricize()
    utl.progress('Construct transformed data matrices', 50, cpu_time=_time.time() - start_time)
    psi_y = tdt.basis_decomposition(y, basis_list).transpose(cores=2).matricize()
    utl.progress('Construct transformed data matrices', 100, cpu_time=_time.time() - start_time)

    return psi_x, psi_y
Exemplo n.º 3
0
def plot_eigenfunction(basis_list, eigenvector):
    """Plot eigenfunctions.

    Parameters
    ----------
    basis_list: list of lists of lambda functions
        list of basis functions in every mode
    eigenvector: array
        TEDMD eigenvector
    """

    # normalize eigenvector
    eigenvector = (1 / np.max(eigenvector)) * eigenvector

    plt.rcParams.update({'axes.grid': False})
    plt.figure(dpi=300)

    # evaluate eigenfunction over domain
    grid_size = 100
    dist = 12 / grid_size
    z = np.zeros([grid_size, grid_size])
    for i in range(grid_size):
        for j in range(grid_size):
            x_tmp = np.array([-6 + i * dist, -6 + j * dist])[:, None]
            z[i, j] = tdt.basis_decomposition(x_tmp, basis_list).matricize().dot(eigenvector)

    plt.imshow(z, cmap='seismic', vmin=-1, vmax=1)
    plt.colorbar()
    plt.xticks([0, (grid_size - 1) / 2, grid_size - 1], [-6, 0, 6])
    plt.yticks([0, (grid_size - 1) / 2, grid_size - 1], [-6, 0, 6])
    plt.xlim([0, grid_size - 1])
    plt.ylim([0, grid_size - 1])
    plt.xlabel(r'$x_1$')
    plt.ylabel(r'$x_2$')
    plt.rcParams.update({'axes.grid': True})
Exemplo n.º 4
0
    def test_basis_decomposition(self):
        """test construction of transformed data tensors"""

        tdt_1 = tdt.basis_decomposition(self.data, self.phi_1).transpose(cores=[self.d]).matricize()
        tdt_2 = np.zeros([3 ** self.d, self.m])
        for j in range(self.m):
            v = [1, self.data[0, j], self.data[0, j] ** 2]
            for i in range(1, self.d):
                v = np.kron(v, [1, self.data[i, j], self.data[i, j] ** 2])
            tdt_2[:, j] = v
        self.assertEqual(np.sum(np.abs(tdt_1 - tdt_2)), 0)

        tdt_1 = tdt.basis_decomposition(self.data, self.phi_1)
        core_0 = tdt.basis_decomposition(self.data, self.phi_1, single_core=0)
        core_1 = tdt.basis_decomposition(self.data, self.phi_1, single_core=1)
        self.assertEqual(np.sum(np.abs(tdt_1.cores[0] - core_0)), 0)
        self.assertEqual(np.sum(np.abs(tdt_1.cores[1] - core_1)), 0)
Exemplo n.º 5
0
    def test_coordinate_major(self):
        """test coordinate-major decomposition"""

        tdt_1 = tdt.basis_decomposition(self.data, self.phi_1)
        tdt_2 = tdt.coordinate_major(self.data, self.psi_1)
        self.assertLess((tdt_1 - tdt_2).norm(), self.tol)

        core_0 = tdt.coordinate_major(self.data, self.psi_1, single_core=0)
        core_1 = tdt.coordinate_major(self.data, self.psi_1, single_core=1)
        self.assertEqual(np.sum(np.abs(tdt_1.cores[0] - core_0)), 0)
        self.assertEqual(np.sum(np.abs(tdt_1.cores[1] - core_1)), 0)
Exemplo n.º 6
0
    def test_function_major(self):
        """test function-major decomposition"""

        tdt_1 = tdt.basis_decomposition(self.data, self.phi_2)
        _ = tdt.function_major(self.data, self.psi_2, add_one=False)
        _ = tdt.function_major(self.data, self.psi_2, add_one=False, single_core=0)
        _ = tdt.function_major(self.data, self.psi_2, add_one=False, single_core=1)
        tdt_2 = tdt.function_major(self.data, self.psi_2)
        self.assertLess((tdt_1 - tdt_2).norm(), self.tol)

        core_0 = tdt.function_major(self.data, self.psi_2, single_core=0)
        core_1 = tdt.function_major(self.data, self.psi_2, single_core=1)
        self.assertEqual(np.sum(np.abs(tdt_1.cores[0] - core_0)), 0)
        self.assertEqual(np.sum(np.abs(tdt_1.cores[1] - core_1)), 0)
Exemplo n.º 7
0
    def test_hocur(self):
        """test higher-order CUR decomposition"""

        tdt_1 = tdt.basis_decomposition(self.data, self.phi_1).transpose(cores=[self.d]).matricize()
        tdt_2 = tdt.hocur(self.data, self.phi_1, 5, repeats=10, progress=False).transpose(cores=[self.d]).matricize()
        self.assertLess(np.sum(np.abs(tdt_1-tdt_2)), self.tol)








        
        
Exemplo n.º 8
0
    def test_mandy_kb(self):
        """test kernel-based approach"""

        # apply kernel-based MANDy
        z = reg.mandy_kb(self.kuramoto_x, self.kuramoto_y, self.kuramoto_basis)

        # construct coefficient tensor
        xi = tdt.basis_decomposition(self.kuramoto_x, self.kuramoto_basis)
        xi.cores[-1] = np.tensordot(xi.cores[-1], z.T,
                                    axes=(1, 0)).transpose([0, 3, 1, 2])
        xi.row_dims[-1] = z.shape[0]

        # compute relative error
        rel_err = (xi - self.kuramoto_xi_exact
                   ).norm() / self.kuramoto_xi_exact.norm()

        # check if relative error is smaller than tolerance
        self.assertLess(rel_err, self.tol)
Exemplo n.º 9
0
def amuset_hosvd(data_matrix, x_indices, y_indices, basis_list, threshold=1e-2, progress=False):
    """
    AMUSEt (AMUSE on tensors) using HOSVD.

    Apply tEDMD to a given data matrix by using AMUSEt with HOSVD. This procedure is a tensor-based
    version of AMUSE using the tensor-train format. For more details, see [1]_.

    Parameters
    ----------
    data_matrix : np.ndarray
        snapshot matrix
    x_indices : np.ndarray or list[np.ndarray]
        index sets for snapshot matrix x
    y_indices : np.ndarray or list[np.ndarray]
        index sets for snapshot matrix y
    basis_list : list[list[function]]
        list of basis functions in every mode
    threshold : float, optional
        threshold for SVD/HOSVD, default is 1e-2
    progress : boolean, optional
        whether to show progress bar, default is False

    Returns
    -------
    eigenvalues : np.ndarray or list[np.ndarray]
        tEDMD eigenvalues
    eigentensors : TT or list[TT]
        tEDMD eigentensors in TT format

    References
    ----------
    ..[1] F. Nüske, P. Gelß, S. Klus, C. Clementi. "Tensor-based EDMD for the Koopman analysis of high-dimensional
          systems", arXiv:1908.04741, 2019
    """

    # define quantities
    eigenvalues = []
    eigentensors = []

    # construct transformed data tensor in TT format using direct approach
    psi = tdt.basis_decomposition(data_matrix, basis_list)

    # left-orthonormalization
    psi = psi.ortho_left(threshold=threshold, progress=progress)

    # extract last core
    last_core = psi.cores[-1]

    # convert x_indices and y_indices to lists
    if not isinstance(x_indices, list):
        x_indices = [x_indices]
        y_indices = [y_indices]

    # loop over all index sets
    for i in range(len(x_indices)):
        # compute reduced matrix
        matrix, u, s, v = _reduced_matrix(last_core, x_indices[i], y_indices[i])

        # solve reduced eigenvalue problem
        eigenvalues_reduced, eigenvectors_reduced = np.linalg.eig(matrix)
        idx = (np.abs(eigenvalues_reduced - 1)).argsort()
        eigenvalues_reduced = np.real(eigenvalues_reduced[idx])
        eigenvectors_reduced = np.real(eigenvectors_reduced[:, idx])

        # construct eigentensors
        eigentensors_tmp = psi
        eigentensors_tmp.cores[-1] = u.dot(np.diag(np.reciprocal(s))).dot(eigenvectors_reduced)[:, :, None, None]

        # append results
        eigenvalues.append(eigenvalues_reduced)
        eigentensors.append(eigentensors_tmp)

    # only return lists if more than one set of x-indices/y-indices was given
    if len(x_indices) == 1:
        eigenvalues = eigenvalues[0]
        eigentensors = eigentensors[0]

    return eigenvalues, eigentensors
Exemplo n.º 10
0
def amuset_hosvd(data_matrix, basis_list, b, sigma, num_eigvals=np.infty, threshold=1e-2, max_rank=np.infty,
                 return_option='eigenfunctionevals'):
    """
    AMUSEt algorithm for the calculation of eigenvalues of the Koopman generator.
    The tensor-trains are created using the exact TT decomposition, whose ranks are reduced using SVDs.
    An efficient implementation of tensor contractions that exploits the special structure of the cores is used.

    Parameters
    ----------
    data_matrix : np.ndarray
        snapshot matrix, shape (d, m)
    basis_list : list[list[Function]]
        list of basis functions in every mode
    b : np.ndarray
        drift, shape (d, m)
    sigma : np.ndarray
        diffusion, shape (d, d2, m)
    num_eigvals : int, optional
        number of eigenvalues and eigentensors that are returned
        default: return all calculated eigenvalues and eigentensors
    threshold : float, optional
        threshold for svd of psi
    max_rank : int, optional
        maximal rank of TT representations of psi after svd/ortho
    return_option : {'eigentensors', 'eigenfunctionevals', 'eigenvectors'}
        'eigentensors': return a list of the eigentensors of the koopman generator
        'eigenfunctionevals': return the evaluations of the eigenfunctions of the koopman generator at all snapshots
        'eigenvectors': eigenvectors of M in AMUSEt

    Returns
    -------
    eigvals : np.ndarray
        eigenvalues of Koopman generator
    eigtensors : list[TT] or np.ndarray
        eigentensors of Koopman generator or evaluations of eigenfunctions at snapshots (shape (*, m))
        (cf. return_option)
    """

    print('calculating Psi(X)...')
    psi = basis_decomposition(data_matrix, basis_list)
    p = psi.order - 1
    # SVD of psi
    u, s, v = psi.svd(p, threshold=threshold, max_rank=max_rank, ortho_l=True, ortho_r=False)
    s_inv = np.diag(1.0 / s)
    psi = u.rank_tensordot(np.diag(s))
    psi.concatenate(v, overwrite=True)  # rank reduced version
    v = (v.cores[0][:, :, 0, 0]).T  # translate v from TT to np.ndarray
    print('Psi(X): {}'.format(psi))

    print('calculating M in AMUSEt')
    M = _amuset_efficient(u, s, v, data_matrix, basis_list, b, sigma)

    print('calculating eigenvalues and eigentensors...')
    # calculate eigenvalues of M
    eigvals, eigvecs = np.linalg.eig(M)

    sorted_indices = np.argsort(-eigvals)
    eigvals = eigvals[sorted_indices]
    eigvecs = eigvecs[:, sorted_indices]

    if not (eigvals < 0).all():
        print('WARNING: there are eigenvalues >= 0')

    if len(eigvals) > num_eigvals:
        eigvals = eigvals[:num_eigvals]
        eigvecs = eigvecs[:, :num_eigvals]

    u.rank_tensordot(s_inv, mode='last', overwrite=True)

    # calculate eigentensors
    if return_option == 'eigentensors':
        eigvecs = eigvecs[:, :, np.newaxis]
        eigtensors = []
        for i in range(eigvals.shape[0]):
            eigtensor = u.copy()
            eigtensor.rank_tensordot(eigvecs[:, i, :], overwrite=True)
            eigtensors.append(eigtensor)
        return eigvals, eigtensors

    elif return_option == 'eigenfunctionevals':
        u.rank_tensordot(eigvecs, overwrite=True)
        u.tensordot(psi, p, mode='first-first', overwrite=True)
        u = u.cores[0][0, :, 0, :].T
        return eigvals, u

    else:
        return eigvals, eigvecs