.. _program_listing_file_include_Suzuki-Trotter-Evolver_UnitaryEvolver.hpp: Program Listing for File UnitaryEvolver.hpp =========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/Suzuki-Trotter-Evolver/UnitaryEvolver.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include #include #include #include #include using std::complex; using std::vector; using Eigen::Dynamic; using std::pow; using std::conj; namespace Suzuki_Trotter_Evolver { template using DMatrix = Eigen::Matrix, n, m>; typedef Eigen::SparseMatrix> SMatrix; template> struct UnitaryEvolver { private: const complex minus_i = complex(0.0, -1.0); public: static const int dim_x_n_ctrl = (dim == Dynamic || n_ctrl == Dynamic) ? Dynamic : dim * n_ctrl; size_t length; Eigen::Array, dim, 1> d0; vector, dim, 1>> ds; Matrix u0; Matrix u0_inverse; vector us; vector us_individual; vector us_inverse_individual; vector hs; Matrix u0_inverse_u_last; template UnitaryEvolver(std::enable_if_t>::value, DMatrix> drift_hamiltonian, DMatrix control_hamiltonians ) { typedef Eigen::SelfAdjointEigenSolver> EigSolver; EigSolver eigs0(drift_hamiltonian); d0 = minus_i*eigs0.eigenvalues().array(); u0 = eigs0.eigenvectors(); u0_inverse = u0.adjoint(); Eigen::Index l = drift_hamiltonian.rows(); length = control_hamiltonians.rows()/control_hamiltonians.cols(); if (length == 0) { u0_inverse_u_last = DMatrix::Identity(l, l); us.push_back(u0); } else { hs.push_back((DMatrix)(control_hamiltonians.block(0, 0, l, l))); EigSolver eigs(hs.back()); ds.push_back((Eigen::Array, dim, 1>)( minus_i*eigs.eigenvalues().array())); DMatrix u = eigs.eigenvectors(); us_individual.push_back(u); us_inverse_individual.push_back(u.adjoint()); us.push_back(u.adjoint() * u0); us.push_back(u); // append twice for (size_t i = 1; i < length; i++) { hs.push_back((DMatrix)(control_hamiltonians.block(i*l, 0, l, l))); eigs = EigSolver(hs.back()); ds.push_back((Eigen::Array, dim, 1>)( minus_i*eigs.eigenvalues().array())); u = eigs.eigenvectors(); us_individual.push_back(u); us_inverse_individual.push_back(u.adjoint()); us.back() = u.adjoint() * us.back(); us.push_back(u); } u0_inverse_u_last.noalias() = u0_inverse * u; } }; // Sparse initialisation template UnitaryEvolver(std::enable_if_t::value, DMatrix> drift_hamiltonian, DMatrix control_hamiltonians) { typedef Eigen::SelfAdjointEigenSolver> EigSolver; EigSolver eigs0(drift_hamiltonian); d0 = minus_i*eigs0.eigenvalues().array(); u0 = eigs0.eigenvectors().sparseView(); u0_inverse = u0.adjoint(); Eigen::Index l = drift_hamiltonian.rows(); length = control_hamiltonians.rows()/control_hamiltonians.cols(); if (length == 0) { u0_inverse_u_last = DMatrix::Identity(l, l).sparseView(); us.push_back(u0); } else { hs.push_back(control_hamiltonians.block(0, 0, l, l).sparseView()); EigSolver eigs((DMatrix)(hs.back())); ds.push_back((Eigen::Array, dim, 1>)( minus_i*eigs.eigenvalues().array())); Matrix u = eigs.eigenvectors().sparseView(); us_individual.push_back(u); us_inverse_individual.push_back(u.adjoint()); us.push_back((u.adjoint() * u0).pruned()); us.push_back(u); // append twice for (size_t i = 1; i < length; i++) { hs.push_back(control_hamiltonians.block(i*l, 0, l, l).sparseView()); eigs = EigSolver((DMatrix)(hs.back())); ds.push_back((Eigen::Array, dim, 1>)( minus_i*eigs.eigenvalues().array())); u = eigs.eigenvectors().sparseView(); us_individual.push_back(u); us_inverse_individual.push_back(u.adjoint()); us.back() = (u.adjoint() * us.back()).pruned(); us.push_back(u); } u0_inverse_u_last = u0_inverse * u; } }; UnitaryEvolver(size_t l, Eigen::Array, dim, 1> d0, vector, dim, 1>> ds, Matrix u0, Matrix u0_inverse, vector us, vector us_individual, vector us_inverse_individual, vector hs, Matrix u0_inverse_u_last) : length{l}, d0{d0}, ds{ds}, u0{u0}, u0_inverse{u0_inverse}, us{us}, us_individual{us_individual}, us_inverse_individual{us_inverse_individual}, hs{hs}, u0_inverse_u_last{u0_inverse_u_last} {}; DMatrix propagate(DMatrix ctrl_amp, DMatrix state, double dt) { size_t steps = ctrl_amp.rows(); DMatrix exp_d0 = (d0*dt).exp().matrix(); ctrl_amp *= dt; state = u0_inverse * state; state = state.cwiseProduct(exp_d0); for (size_t j = 0; j < length; j++) { state = us[j] * state; state = state.cwiseProduct((ds[j]*ctrl_amp(0, j)).exp().matrix()); } for (size_t i = 1; i < steps; i++) { state = u0_inverse_u_last * state; state = state.cwiseProduct(exp_d0); for (size_t j = 0; j < length; j++) { state = us[j] * state; state = state.cwiseProduct( (ds[j]*ctrl_amp(i, j)).exp().matrix()); } } state = us[length] * state; return state; }; template DMatrix propagate_collection(DMatrix ctrl_amp, DMatrix states, double dt) { size_t steps = ctrl_amp.rows(); Eigen::Array, dim, 1> exp_d0 = (d0*dt).exp(); ctrl_amp *= dt; states = u0_inverse*states; states = states.array().colwise() * exp_d0; for (size_t j = 0; j < length; j++) { states = us[j] * states; states = states.array().colwise() * (ds[j]*ctrl_amp(0, j)).exp(); } for (size_t i = 1; i < steps; i++) { states = u0_inverse_u_last * states; states = states.array().colwise() * exp_d0; for (size_t j = 0; j < length; j++) { states = us[j] * states; states = states.array().colwise() *(ds[j]*ctrl_amp(i, j)).exp(); } } states = us[length] * states; return states; }; DMatrix propagate_all(DMatrix ctrl_amp, DMatrix state, double dt) { size_t steps = ctrl_amp.rows(); DMatrix exp_d0 = (d0*dt).exp().matrix(); DMatrix phi(state.rows(), steps+1); ctrl_amp *= dt; phi.col(0) = state; phi.col(1) = u0_inverse * state; phi.col(1) = phi.col(1).cwiseProduct(exp_d0); for (size_t j = 0; j < length; j++) { phi.col(1) = us[j] * phi.col(1); phi.col(1) = phi.col(1).cwiseProduct( (ds[j]*ctrl_amp(0, j)).exp().matrix()); } phi.col(1) = us[length] * phi.col(1); for (size_t i = 1, k = 2; i < steps; i++, k++) { phi.col(k) = u0_inverse * phi.col(i); phi.col(k) = phi.col(k).cwiseProduct(exp_d0); for (size_t j = 0; j < length; j++) { phi.col(k) = us[j] * phi.col(k); phi.col(k) = phi.col(k).cwiseProduct( (ds[j]*ctrl_amp(i, j)).exp().matrix()); } phi.col(k) = us[length] * phi.col(k); } return phi; }; complex evolved_expectation_value(DMatrix ctrl_amp, DMatrix state, double dt, DMatrix observable) { state = propagate(ctrl_amp, state, dt); return state.dot(observable * state); // dot conjugates and transposes }; DMatrix evolved_expectation_value_all( DMatrix ctrl_amp, DMatrix state, double dt, DMatrix observable) { DMatrix phi = propagate_all(ctrl_amp, state, dt); return (phi.adjoint() * observable * phi).diagonal(); }; std::tuple, Eigen::Matrix> switching_function(DMatrix ctrl_amp, DMatrix state, double dt, DMatrix cost) { // forward propagation size_t steps = ctrl_amp.rows(); DMatrix exp_d0 = (d0*dt).exp().matrix(); ctrl_amp *= dt; state = u0_inverse * state; state = state.cwiseProduct(exp_d0); for (size_t j = 0; j < length; j++) { state = us[j] * state; state = state.cwiseProduct((ds[j]*ctrl_amp(0, j)).exp().matrix()); } for (size_t i = 1; i < steps; i++) { state = u0_inverse_u_last * state; state = state.cwiseProduct(exp_d0); for (size_t j = 0; j < length; j++) { state = us[j] * state; state = state.cwiseProduct( (ds[j]*ctrl_amp(i, j)).exp().matrix()); } } state = us[length] * state; // Lambda DMatrix lambda = cost * state; // Energy complex E = state.dot(lambda); // Back propagation DMatrix exp_d0_c = exp_d0.conjugate(); ctrl_amp *= -1; DMatrix out = DMatrix::Zero(steps, length); for (size_t k = steps-1; true;) { for (size_t j = length-1; true;) { out(k, j) = lambda.dot(hs[j] * state); state = us_inverse_individual[j] * state; state = state.cwiseProduct( (ds[j]*ctrl_amp(k, j)).exp().matrix()); state = us_individual[j] * state; lambda = us_inverse_individual[j] * lambda; lambda = lambda.cwiseProduct( (ds[j]*ctrl_amp(k, j)).exp().matrix()); lambda = us_individual[j] * lambda; if (j == 0) { break; } j--; } if (k == 0) { break; } state = u0_inverse * state; state = state.cwiseProduct(exp_d0_c); state = u0 * state; lambda = u0_inverse * lambda; lambda = lambda.cwiseProduct(exp_d0_c); lambda = u0 * lambda; k--; } return std::tuple, Eigen::Matrix>( E, 2*out.imag() ); }; }; }