def setUp(self): """Construct a Toeplitz matrix for testing the routines in sle.py""" # set tolerance for the error self.tol = 1e-7 # set order of the resulting TT operator self.order = 10 # generate Toeplitz matrix self.operator_mat = sp.linalg.toeplitz(np.arange(1, 2**self.order + 1), np.arange(1, 2**self.order + 1)) # decompose Toeplitz matrix into TT format self.operator_tt = TT(self.operator_mat.reshape([2] * 2 * self.order)) # define right-hand side as vector of all ones (matrix case) self.rhs_mat = np.ones(self.operator_mat.shape[0]) # define right-hand side as tensor train of all ones (tensor case) self.rhs_tt = tt.ones(self.operator_tt.row_dims, [1] * self.operator_tt.order) # define initial tensor train for solving the system of linear equations self.initial_tt = tt.ones(self.operator_tt.row_dims, [1] * self.operator_tt.order, ranks=5).ortho_right()
def test_errors(self): """test for error computations""" # compute numerical solution of the ODE operator = mdl.signaling_cascade(3).tt2qtt([[2] * 6] * 3, [[2] * 6] * 3) initial_value = tt.unit(operator.row_dims, [0] * operator.order) initial_guess = tt.ones(operator.row_dims, [1] * operator.order, ranks=self.rank).ortho_right() step_sizes = [0.1] * 10 solution_ee = ode.explicit_euler(operator, initial_value, step_sizes, progress=False, max_rank=self.max_rank) solution_ie = ode.implicit_euler(operator, initial_value, initial_guess, step_sizes, progress=False) solution_tr = ode.trapezoidal_rule(operator, initial_value, initial_guess, step_sizes, progress=False) # compute errors errors_ee = ode.errors_expl_euler(operator, solution_ee, step_sizes) errors_ie = ode.errors_impl_euler(operator, solution_ie, step_sizes) errors_tr = ode.errors_trapezoidal(operator, solution_tr, step_sizes) # check if errors are smaller than tolerance self.assertLess(np.max(errors_ee), self.tol) self.assertLess(np.max(errors_ie), self.tol) self.assertLess(np.max(errors_tr), self.tol)
def test_trapezoidal_rule(self): """test for trapezoidal rule""" # compute numerical solution of the ODE operator = mdl.two_step_destruction(1, 2, 1, 2) initial_value = tt.zeros([2 ** 2, 2 ** (2 + 1), 2 ** 2, 2 ** 2], [1] * 4) initial_value.cores[0][0, -1, 0, 0] = 1 initial_value.cores[1][0, -2, 0, 0] = 1 initial_value.cores[2][0, 0, 0, 0] = 1 initial_value.cores[3][0, 0, 0, 0] = 1 initial_guess = tt.ones(operator.row_dims, [1] * operator.order, ranks=self.rank).ortho_right() step_sizes = [0.001] * 100 + [0.1] * 9 + [1] * 19 solution_als = ode.trapezoidal_rule(operator, initial_value, initial_guess, step_sizes, tt_solver='als', progress=False) solution_mals = ode.trapezoidal_rule(operator, initial_value, initial_guess, step_sizes, tt_solver='mals', max_rank=self.rank, progress=False) # compute norm of the derivatives at the final 10 time steps derivatives_als = [] derivatives_mals = [] for i in range(10): derivatives_als.append((operator.dot(solution_als[-i - 1])).norm()) derivatives_mals.append((operator.dot(solution_mals[-i - 1])).norm()) # check if trapezoidal rule converged to stationary distribution for i in range(10): self.assertLess(derivatives_als[i], self.tol) self.assertLess(derivatives_mals[i], self.tol)
def setUp(self): """Consider the triple-well model for testing the routines in sle.py""" # set tolerance for the error of the eigenvalues self.tol_eigval = 1e-3 # set tolerance for the error of the eigenvectors self.tol_eigvec = 5e-2 # set number of eigenvalues to compute self.number_ev = 3 # generate operator in TT format directory = os.path.dirname(os.path.dirname( os.path.realpath(__file__))) transitions = io.loadmat( directory + '/examples/data/TripleWell2D_500.mat')["indices"] self.operator_tt = pf.perron_frobenius_2d(transitions, [50, 50], 500) # matricize TT operator self.operator_mat = self.operator_tt.matricize() # define initial tensor train for solving the eigenvalue problem self.initial_tt = tt.ones(self.operator_tt.row_dims, [1] * self.operator_tt.order, ranks=11).ortho_right()
def test_adaptive(self): """test for adaptive_step_size""" # compute numerical solution of the ODE operator = mdl.signaling_cascade(2).tt2qtt([[2] * 6] * 2, [[2] * 6] * 2) initial_value = tt.unit(operator.row_dims, [0] * operator.order) initial_guess = tt.ones(operator.row_dims, [1] * operator.order, ranks=self.rank).ortho_right() solution_ie, _ = ode.adaptive_step_size(operator, initial_value, initial_guess, 300, step_size_first=1, second_method='two_step_Euler', progress=False) solution_tr, _ = ode.adaptive_step_size( operator, initial_value, initial_guess, 300, step_size_first=1, second_method='trapezoidal_rule', progress=False) # compute norm of the derivatives at the final time step derivative_ie = (operator.dot(solution_ie[-1])).norm() derivative_tr = (operator.dot(solution_tr[-1])).norm() # check if converged to stationary distribution self.assertLess(derivative_ie, self.tol) self.assertLess(derivative_tr, self.tol)
def setUpClass(cls): super(TestEVP, cls).setUpClass() # set tolerance for the error of the eigenvalues cls.tol_eigval = 5e-3 # set tolerance for the error of the eigenvectors cls.tol_eigvec = 5e-2 # set number of eigenvalues to compute cls.number_ev = 3 # load data directory = os.path.dirname(os.path.dirname( os.path.realpath(__file__))) transitions = np.load( directory + '/examples/data/triple_well_transitions.npz')["transitions"] # coarse-grain data transitions = np.int64(np.ceil(np.true_divide(transitions, 2))) # generate operators in TT format cls.operator_tt = ulam.ulam_2d(transitions, [25, 25], 2000) cls.operator_gevp = tt.eye(cls.operator_tt.row_dims) # matricize TT operator cls.operator_mat = cls.operator_tt.matricize() # define initial tensor train for solving the eigenvalue problem cls.initial_tt = tt.ones(cls.operator_tt.row_dims, [1] * cls.operator_tt.order, ranks=15).ortho_right()
def two_cell_tof(t, reactant_states, reaction_rate): """Turn-over frequency of a reaction in a cyclic homogeneous nearest-neighbor interaction system Parameters ---------- t: instance of TT class tensor train representing a probability distribution reactant_states: list of ints reactant states of the given reaction in the form of [reactant_state_1, reactant_state_2] where the list entries represent the reactant states on two neighboring cell reaction_rate: float reaction rate constant of the given reaction Returns ------- turn_over_frequency: float turn-over frequency of the given reaction """ tt_left = [None] * t.order tt_right = [None] * t.order for k in range(t.order): tt_left[k] = tt.ones([1] * t.order, t.row_dims) tt_right[k] = tt.ones([1] * t.order, t.row_dims) tt_left[k].cores[k] = np.zeros([1, 1, t.row_dims[k], 1]) tt_left[k].cores[k][0, 0, reactant_states[0], 0] = 1 tt_right[k].cores[k] = np.zeros([1, 1, t.row_dims[k], 1]) tt_right[k].cores[k][0, 0, reactant_states[0], 0] = 1 if k > 0: tt_left[k].cores[k - 1] = np.zeros([1, 1, t.row_dims[k - 1], 1]) tt_left[k].cores[k - 1][0, 0, reactant_states[1], 0] = 1 else: tt_left[k].cores[-1] = np.zeros([1, 1, t.row_dims[-1], 1]) tt_left[k].cores[-1][0, 0, reactant_states[1], 0] = 1 if k < t.order - 1: tt_right[k].cores[k + 1] = np.zeros([1, 1, t.row_dims[k + 1], 1]) tt_right[k].cores[k + 1][0, 0, reactant_states[1], 0] = 1 else: tt_right[k].cores[0] = np.zeros([1, 1, t.row_dims[0], 1]) tt_right[k].cores[0][0, 0, reactant_states[1], 0] = 1 turn_over_frequency = 0 for k in range(t.order): turn_over_frequency = turn_over_frequency + (reaction_rate / t.order) * (tt_left[k] @ t) + \ (reaction_rate / t.order) * (tt_right[k] @ t) return turn_over_frequency
def test_toll_station(self): """tests for toll station""" # construct operator op = mdl.toll_station(self.number_of_lanes, self.number_of_cars) # check if stochastic self.assertLess((tt.ones([1] * op.order, op.col_dims).dot(op)).norm(), self.tol)
def test_co_oxidation(self): """tests for CO oxidation""" # construct operator op = mdl.co_oxidation(self.order, self.k_ad_co, cyclic=True) # check if stochastic self.assertLess((tt.ones([1] * op.order, op.col_dims).dot(op)).norm(), self.tol)
def test_two_step(self): """tests for two-setp destruction""" # construct operator op = mdl.two_step_destruction(self.k_1, self.k_2, self.k_3, self.m) # check if stochastic self.assertLess((tt.ones([1] * op.order, op.col_dims).dot(op)).norm(), self.tol)
def test_signaling_cascade(self): """tests for signaling cascade""" # construct operator op = mdl.signaling_cascade(self.order) # check if stochastic self.assertLess((tt.ones([1] * op.order, op.col_dims).dot(op)).norm(), self.tol)
def test_ones(self): """test tensor train of all ones""" # construct tensor train of all ones, convert to full format, and flatten t_ones = tt.ones(self.row_dims, self.col_dims).full().flatten() # construct full array of all ones t_full = np.ones(np.int(np.prod(self.row_dims)) * np.int(np.prod(self.col_dims))) # compute relative error rel_err = np.linalg.norm(t_ones - t_full) / np.linalg.norm(t_full) # check if relative error is smaller than tolerance self.assertLess(rel_err, self.tol)
def test_implicit_euler(self): """test for implicit Euler method""" # compute numerical solution of the ODE operator = mdl.signaling_cascade(2).tt2qtt([[2] * 6] * 2, [[2] * 6] * 2) initial_value = tt.unit(operator.row_dims, [0] * operator.order) initial_guess = tt.ones(operator.row_dims, [1] * operator.order, ranks=self.rank).ortho_right() step_sizes = [1] * 300 solution_als = ode.implicit_euler(operator, initial_value, initial_guess, step_sizes, tt_solver='als', progress=False) solution_mals = ode.implicit_euler(operator, initial_value, initial_guess, step_sizes, tt_solver='mals', max_rank=self.rank, progress=False) # compute norm of the derivatives at the final 10 time steps derivatives_als = [] derivatives_mals = [] for i in range(10): derivatives_als.append((operator.dot(solution_als[-i - 1])).norm()) derivatives_mals.append( (operator.dot(solution_mals[-i - 1])).norm()) # check if implicit Euler method converged to stationary distribution for i in range(10): self.assertLess(derivatives_als[i], self.tol) self.assertLess(derivatives_mals[i], self.tol)
# compute solutions and print results # ----------------------------------- print('----------------------------------------------------------') print('p_CO in atm Method TT ranks Closeness CPU time') print('----------------------------------------------------------') # construct eigenvalue problems to find the stationary distributions # ------------------------------------------------------------------ for i in range(8): # construct and solve eigenvalue problem for current CO pressure operator = mdl.co_oxidation( 20, 10**(8 + p_CO_exp[i])).ortho_left().ortho_right() initial_guess = tt.ones(operator.row_dims, [1] * operator.order, ranks=R[i]).ortho_left().ortho_right() with utl.timer() as time: eigenvalues, solution = evp.als(tt.eye(operator.row_dims) + operator, initial_guess, repeats=10, solver='eigs') solution = (1 / solution.norm(p=1)) * solution # compute turn-over frequency of CO2 desorption tof.append(utl.two_cell_tof(solution, [2, 1], 1.7e5)) # print results string_p_CO = '10^' + (p_CO_exp[i] >= 0) * '+' + str("%.1f" % p_CO_exp[i]) string_method = ' ' * 9 + 'EVP' + ' ' * 9 string_rank = (R[i] < 10) * ' ' + str(R[i]) + ' ' * 8 string_closeness = str("%.2e" % (operator @ solution).norm()) + ' ' * 6
# operator in TT format # --------------------- operator = mdl.signaling_cascade(order) # initial distribution in TT format # --------------------------------- initial_distribution = tt.zeros(operator.col_dims, [1] * order) for p in range(initial_distribution.order): initial_distribution.cores[p][0, 0, 0, 0] = 1 # initial guess in TT format # -------------------------- initial_guess = tt.ones(operator.col_dims, [1] * order, ranks=tt_rank).ortho_right() # solve Markovian master equation in TT format # -------------------------------------------- print('TT approach:\n') solution = ode.trapezoidal_rule(operator, initial_distribution, initial_guess, step_sizes) # operator in QTT format # ---------------------- operator = TT.tt2qtt(operator, qtt_modes, qtt_modes, threshold=threshold) # initial distribution in QTT format # ----------------------------------
utl.progress('Load data', 0, dots=39) transitions = io.loadmat("data/TripleWell2D_500.mat")["indices"] utl.progress('Load data', 100, dots=39) # construct TT operator # --------------------- utl.progress('Construct operator', 0, dots=30) operator = pf.perron_frobenius_2d(transitions, [n_states, n_states], simulations) utl.progress('Construct operator', 100, dots=30) # approximate leading eigenfunctions of the Perron-Frobenius and Koopman operator # ------------------------------------------------------------------------------- initial = tt.ones(operator.row_dims, [1] * operator.order, ranks=11) utl.progress('Approximate eigenfunctions in the TT format', 0, dots=5) eigenvalues_pf, eigenfunctions_pf = evp.als(operator, initial, number_ev, 3) utl.progress('Approximate eigenfunctions in the TT format', 50, dots=5) eigenvalues_km, eigenfunctions_km = evp.als(operator.transpose(), initial, number_ev, 2) utl.progress('Approximate eigenfunctions in the TT format', 100, dots=5) # compute exact eigenvectors # -------------------------- utl.progress('Compute exact eigenfunctions in matrix format', 0) eigenvalues_pf_exact, eigenfunctions_pf_exact = splin.eigs( operator.matricize(), k=number_ev) utl.progress('Compute exact eigenfunctions in matrix format', 100)
def setUp(self): """Consider the Fermi-Pasta-Ulam problem and Kuramoto model for testing the routines in sle.py""" # set tolerance self.tol = 1e-5 # number of oscillators self.fpu_d = 4 self.kuramoto_d = 10 # parameters for the Fermi-Pasta_ulam problem self.fpu_m = 2000 self.fpu_psi = [ lambda t: 1, lambda t: t, lambda t: t**2, lambda t: t**3 ] # parameters for the Kuramoto model self.kuramoto_x_0 = 2 * np.pi * np.random.rand(self.kuramoto_d) - np.pi self.kuramoto_w = np.linspace(-5, 5, self.kuramoto_d) self.kuramoto_t = 100 self.kuramoto_m = 1000 self.kuramoto_psi = [lambda t: np.sin(t), lambda t: np.cos(t)] self.kuramoto_basis = [[tdt.constant_function()] + [tdt.sin(i, 1) for i in range(self.kuramoto_d)], [tdt.constant_function()] + [tdt.cos(i, 1) for i in range(self.kuramoto_d)]] self.kuramoto_initial = tt.ones([11, 11], [1, 1], 11) # exact coefficient tensors self.fpu_xi_exact = mdl.fpu_coefficients(self.fpu_d) self.kuramoto_xi_exact = mdl.kuramoto_coefficients( self.kuramoto_d, self.kuramoto_w) # generate test data for FPU self.fpu_x = 0.2 * np.random.rand(self.fpu_d, self.fpu_m) - 0.1 self.fpu_y = np.zeros((self.fpu_d, self.fpu_m)) for j in range(self.fpu_m): self.fpu_y[0, j] = self.fpu_x[1, j] - 2 * self.fpu_x[0, j] + 0.7 * ( (self.fpu_x[1, j] - self.fpu_x[0, j])**3 - self.fpu_x[0, j]**3) for i in range(1, self.fpu_d - 1): self.fpu_y[i, j] = self.fpu_x[ i + 1, j] - 2 * self.fpu_x[i, j] + self.fpu_x[i - 1, j] + 0.7 * ( (self.fpu_x[i + 1, j] - self.fpu_x[i, j])**3 - (self.fpu_x[i, j] - self.fpu_x[i - 1, j])**3) self.fpu_y[-1, j] = -2 * self.fpu_x[-1, j] + self.fpu_x[ -2, j] + 0.7 * (-self.fpu_x[-1, j]**3 - (self.fpu_x[-1, j] - self.fpu_x[-2, j])**3) # generate test data for Kuramoto number_of_oscillators = len(self.kuramoto_x_0) def kuramoto_ode(_, theta): [theta_i, theta_j] = np.meshgrid(theta, theta) return self.kuramoto_w + 2 / number_of_oscillators * np.sin( theta_j - theta_i).sum(0) + 0.2 * np.sin(theta) sol = spint.solve_ivp(kuramoto_ode, [0, self.kuramoto_t], self.kuramoto_x_0, method='BDF', t_eval=np.linspace(0, self.kuramoto_t, self.kuramoto_m)) self.kuramoto_x = sol.y self.kuramoto_y = np.zeros([number_of_oscillators, self.kuramoto_m]) for i in range(self.kuramoto_m): self.kuramoto_y[:, i] = kuramoto_ode(0, self.kuramoto_x[:, i])