예제 #1
0
def als(operator,
        initial_guess,
        previous=[],
        shift=0,
        operator_gevp=None,
        number_ev=1,
        repeats=1,
        conv_eps=1e-8,
        solver='eig',
        sigma=1,
        real=True):
    """
    Alternating linear scheme.

    Approximates eigenvalues and corresponding eigentensors of an (generalized) eigenvalue problem in the TT format.
    For details, see [1]_.

    Parameters
    ----------
    operator : TT
        TT operator, left-hand side
    initial_guess : TT
        initial guess for the solution
    previous : list of TT, optional
        list of known eigentensors whose eigenvalues should be shifted
    shift : float, optional
        shift parameter for known eigenpairs
    operator_gevp : TT, optional
        TT operator, right-hand side (for generalized eigenvalue problems), default is None
    number_ev : int, optional
        number of eigenvalues and corresponding eigentensor to compute, default is 1
    repeats : int, optional
        number of repeats of the ALS, default is 1
    conv_eps : float, optional
        threshold for convergence of the eigenvalue, default is 0
    solver : string, optional
        algorithm for obtaining the solutions of the micro systems, can be 'eig', 'eigs' or 'eigh', default is 'eig'
    sigma : float, optional
        find eigenvalues near sigma, default is 1
    real : bool, optional
        whether to compute only real eigenvalues and eigentensors or not, default is True

    Returns
    -------
    eigenvalues: float or list[float]
        approximated eigenvalues, if number_ev>1 eigenvalues is a list[float]
    eigentensors: TT or list[TT]
        approximated eigentensors, if number_ev>1 eigentensors is a list of tensor trains

    References
    ----------
    ..[1] S. Holtz, T. Rohwedder, R. Schneider, "The Alternating Linear Scheme for Tensor Optimization in the Tensor
          Train Format", SIAM Journal on Scientific Computing 34 (2), 2012
    """

    # define tensor trains
    trains = Object()
    trains.operator = operator
    trains.operator_gevp = operator_gevp
    trains.solution = initial_guess.copy()
    trains.previous = previous

    # define stacks
    stacks = Object()
    stacks.op_left = [None] * operator.order
    stacks.op_right = [None] * operator.order
    stacks.op_gevp_left = [None] * operator.order
    stacks.op_gevp_right = [None] * operator.order
    stacks.previous_left = [[None] * operator.order
                            for _ in range(len(previous))]
    stacks.previous_right = [[None] * operator.order
                             for _ in range(len(previous))]

    # construct right stacks for the left-hand side
    for i in range(operator.order - 1, -1, -1):
        __construct_right_stacks(i, trains, stacks)

    # define iteration number
    current_iteration = 1

    # initialize variables for convergence detection
    eigenvalues_pre = np.array([np.infty] * number_ev)[None, :]
    conv_tf = False

    # begin ALS
    while current_iteration <= repeats and not conv_tf:

        # first half sweep
        for i in range(operator.order):

            # update left stack for the left-hand side
            __construct_left_stacks(i, trains, stacks)

            if i < operator.order - 1:

                # construct micro system
                micro_op, micro_op_gevp = __construct_micro_matrices(
                    i, trains, stacks, shift)

                # update solution
                eigenvalues = __update_core(i, micro_op, micro_op_gevp,
                                            number_ev, trains.solution, solver,
                                            sigma, real, 'forward')

        # second half sweep
        for i in range(operator.order - 1, -1, -1):
            # update right stack for the left-hand side
            __construct_right_stacks(i, trains, stacks)

            # construct micro system
            micro_op, micro_op_gevp = __construct_micro_matrices(
                i, trains, stacks, shift)

            # update solution
            eigenvalues = __update_core(i, micro_op, micro_op_gevp, number_ev,
                                        trains.solution, solver, sigma, real,
                                        'backward')

        # increase iteration number
        current_iteration += 1

        # check for convergence
        last = eigenvalues_pre[-np.amin([3, eigenvalues_pre.shape[0]]):, :]
        # last_rel_diff = np.abs(np.dot(last - eigenvalues, np.diag(np.reciprocal(eigenvalues))))
        last_diff = np.abs(last - eigenvalues)
        if np.amax(last_diff) < conv_eps:
            conv_tf = True
        eigenvalues_pre = np.vstack((eigenvalues_pre, eigenvalues))

    # define form of the final solution depending on the number of eigenvalues to compute
    if number_ev == 1:
        eigentensors = TT([trains.solution.cores[0][:, :, :, :, 0]] +
                          trains.solution.cores[1:])
        eigenvalues = eigenvalues[0]
    else:
        eigentensors = []
        for i in range(number_ev):
            eigentensors.append(
                TT([trains.solution.cores[0][:, :, :, :, i]] +
                   trains.solution.cores[1:]))

    return eigenvalues, eigentensors
예제 #2
0
파일: evp.py 프로젝트: kiwikuma/scikit_tt
def als(operator, initial_guess, operator_gevp=None, number_ev=1, repeats=1, solver='eig', sigma=1, real=True):
    """Alternating linear scheme

    Approximates eigenvalues and corresponding eigentensors of an (generalized) eigenvalue problem in the TT format.
    For details, see [1]_.

    Parameters
    ----------
    operator: instance of TT class
        TT operator, left-hand side
    initial_guess: instance of TT class
        initial guess for the solution
    operator_gevp: instance of TT class, optional
        TT operator, right-hand side (for generalized eigenvalue problems), default is None
    number_ev: int, optional
        number of eigenvalues and corresponding eigentensor to compute, default is 1
    repeats: int, optional
        number of repeats of the ALS, default is 1
    solver: string, optional
        algorithm for obtaining the solutions of the micro systems, can be 'eig', 'eigs' or 'eigh', default is 'eig'
    sigma: float, optional
        find eigenvalues near sigma, default is 1
    real: bool, optional
        whether to compute only real eigenvalues and eigentensors or not, default is True

    Returns
    -------
    eigenvalues: float or list of floats
        approximated eigenvalues, if number_ev>1 eigenvalues is a list of floats
    eigentensors: instance of TT class or list of instances of TT class
        approximated eigentensors, if number_ev>1 eigentensors is a list of tensor trains

    References
    ----------
    ..[1] S. Holtz, T. Rohwedder, R. Schneider, "The Alternating Linear Scheme for Tensor Optimization in the Tensor
          Train Format", SIAM Journal on Scientific Computing 34 (2), 2012
    """

    # define solution tensor and eigenvalues
    solution = initial_guess.copy()
    eigenvalues = None

    # define stacks
    stack_left_op = [None] * operator.order
    stack_right_op = [None] * operator.order
    stack_left_op_gevp = [None] * operator.order
    stack_right_op_gevp = [None] * operator.order

    # define micro operator for generalized eigenvalue problems
    micro_op_gevp = None

    # construct right stacks for the left-hand side
    for i in range(operator.order - 1, -1, -1):
        __construct_stack_right_op(i, stack_right_op, operator, solution)

    # construct right stacks for the right-hand side
    if operator_gevp is not None:
        for i in range(operator.order - 1, -1, -1):
            __construct_stack_right_op(i, stack_right_op_gevp, operator_gevp, solution)

    # define iteration number
    current_iteration = 1

    # begin ALS
    while current_iteration <= repeats:

        # first half sweep
        for i in range(operator.order):

            # update left stack for the left-hand side
            __construct_stack_left_op(i, stack_left_op, operator, solution)

            # update left stack for the right-hand side
            if operator_gevp is not None:
                __construct_stack_left_op(i, stack_left_op_gevp, operator_gevp, solution)

            if i < operator.order - 1:

                # construct micro system
                micro_op = __construct_micro_matrix_als(i, stack_left_op, stack_right_op, operator, solution)
                if operator_gevp is not None:
                    micro_op_gevp = __construct_micro_matrix_als(i, stack_left_op_gevp, stack_right_op_gevp,
                                                                 operator_gevp, solution)

                # update solution
                eigenvalues = __update_core_als(i, micro_op, micro_op_gevp, number_ev, solution, solver, sigma, real,
                                                'forward')

        # second half sweep
        for i in range(operator.order - 1, -1, -1):
            # update right stack for the left-hand side
            __construct_stack_right_op(i, stack_right_op, operator, solution)

            # update right stack for the right-hand side
            if operator_gevp is not None:
                __construct_stack_right_op(i, stack_right_op_gevp, operator_gevp, solution)

            # construct micro system
            micro_op = __construct_micro_matrix_als(i, stack_left_op, stack_right_op, operator, solution)
            if operator_gevp is not None:
                micro_op_gevp = __construct_micro_matrix_als(i, stack_left_op_gevp, stack_right_op_gevp, operator_gevp,
                                                             solution)

            # update solution
            eigenvalues = __update_core_als(i, micro_op, micro_op_gevp, number_ev, solution, solver, sigma, real,
                                            'backward')

        # increase iteration number
        current_iteration += 1

    # define form of the final solution depending on the number of eigenvalues to compute
    if number_ev == 1:
        eigentensors = TT([solution.cores[0][:, :, :, :, 0]] + solution.cores[1:])
        eigenvalues = eigenvalues[0]
    else:
        eigentensors = []
        for i in range(number_ev):
            eigentensors.append(TT([solution.cores[0][:, :, :, :, i]] + solution.cores[1:]))

    return eigenvalues, eigentensors