Program Listing for File UnitaryEvolver.hpp¶
↰ Return to documentation for file (include/Suzuki-Trotter-Evolver/UnitaryEvolver.hpp)
#include <complex>
#include <cmath>
#include <vector>
#include <Eigen/Eigenvalues>
#include <Eigen/SparseCore>
using std::complex;
using std::vector;
using Eigen::Dynamic;
using std::pow;
using std::conj;
namespace Suzuki_Trotter_Evolver {
template<int n = Dynamic, int m = Dynamic> using DMatrix =
Eigen::Matrix<complex<double>, n, m>;
typedef Eigen::SparseMatrix<complex<double>> SMatrix;
template <typename Derived>
double unitary_gate_infidelity(const Eigen::MatrixBase<Derived>& gate,
const Eigen::MatrixBase<Derived>& target) {
Eigen::Index d = target.rows();
return 1-(std::pow(std::abs((target.adjoint()*gate).trace()),2)+d) /
(d*(d+1));
};
template<int n_ctrl = Dynamic,
int dim = Dynamic,
typename Matrix = DMatrix<dim, dim>>
struct UnitaryEvolver {
private: const complex<double> minus_i = complex<double>(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<complex<double>, dim, 1> d0;
vector<Eigen::Array<complex<double>, dim, 1>> ds;
Matrix u0;
Matrix u0_inverse;
vector<Matrix> us;
vector<Matrix> us_individual;
vector<Matrix> us_inverse_individual;
vector<Matrix> hs;
Matrix u0_inverse_u_last;
template<typename T = Matrix>
UnitaryEvolver(std::enable_if_t<std::is_same<T, DMatrix<dim, dim>>::value,
DMatrix<dim, dim>> drift_hamiltonian,
DMatrix<dim_x_n_ctrl, dim> control_hamiltonians
) {
typedef Eigen::SelfAdjointEigenSolver<DMatrix<dim, dim>> 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<dim, dim>::Identity(l, l);
us.push_back(u0);
} else {
hs.push_back(
(DMatrix<dim, dim>)(control_hamiltonians.block(0, 0, l, l)));
EigSolver eigs(hs.back());
ds.push_back((Eigen::Array<complex<double>, dim, 1>)(
minus_i*eigs.eigenvalues().array()));
DMatrix<dim, dim> 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<dim, dim>)(control_hamiltonians.block(
i*l, 0, l, l)));
eigs = EigSolver(hs.back());
ds.push_back((Eigen::Array<complex<double>, 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<typename T = Matrix>
UnitaryEvolver(std::enable_if_t<std::is_same<T, SMatrix>::value,
DMatrix<dim, dim>> drift_hamiltonian,
DMatrix<dim_x_n_ctrl, dim> control_hamiltonians) {
typedef Eigen::SelfAdjointEigenSolver<DMatrix<dim, dim>> 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<dim, dim>::Identity(l, l).sparseView();
us.push_back(u0);
} else {
hs.push_back(control_hamiltonians.block(0, 0, l, l).sparseView());
EigSolver eigs((DMatrix<dim, dim>)(hs.back()));
ds.push_back((Eigen::Array<complex<double>, 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<dim, dim>)(hs.back()));
ds.push_back((Eigen::Array<complex<double>, 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<complex<double>, dim, 1> d0,
vector<Eigen::Array<complex<double>, dim, 1>> ds,
Matrix u0,
Matrix u0_inverse,
vector<Matrix> us,
vector<Matrix> us_individual,
vector<Matrix> us_inverse_individual,
vector<Matrix> control_hamiltonians,
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{control_hamiltonians},
u0_inverse_u_last{u0_inverse_u_last}
{};
DMatrix<dim, 1> propagate(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, 1> state,
double dt) {
size_t steps = ctrl_amp.rows();
DMatrix<dim, 1> 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<int l = Dynamic>
DMatrix<dim, l> propagate_collection(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, l> states,
double dt) {
size_t steps = ctrl_amp.rows();
Eigen::Array<complex<double>, 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<dim, Dynamic> propagate_all(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, 1> state,
double dt) {
size_t steps = ctrl_amp.rows();
DMatrix<dim, 1> exp_d0 = (d0*dt).exp().matrix();
DMatrix<dim, Dynamic> 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<double> evolved_expectation_value(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, 1> state,
double dt,
DMatrix<dim, dim> observable) {
state = propagate(ctrl_amp, state, dt);
return state.dot(observable * state); // dot conjugates and transposes
};
DMatrix<Dynamic, 1>
evolved_expectation_value_all(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, 1> state,
double dt,
DMatrix<dim, dim> observable) {
DMatrix<dim, Dynamic> phi = propagate_all(ctrl_amp, state, dt);
return (phi.adjoint() * observable * phi).diagonal();
};
complex<double> evolved_inner_product(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, 1> state,
double dt,
DMatrix<1, dim> fixed_vector) {
state = propagate(ctrl_amp, state, dt);
return fixed_vector*state;
};
DMatrix<Dynamic, 1>
evolved_inner_product_all(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, 1> state,
double dt,
DMatrix<1, dim> fixed_vector) {
DMatrix<dim, Dynamic> phi = propagate_all(ctrl_amp, state, dt);
return fixed_vector*phi;
};
std::tuple<complex<double>, Eigen::Matrix<double, Dynamic, n_ctrl>>
switching_function(DMatrix<Dynamic, n_ctrl> ctrl_amp,
DMatrix<dim, 1> state,
double dt,
DMatrix<dim, dim> cost) {
// forward propagation
size_t steps = ctrl_amp.rows();
DMatrix<dim, 1> 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<dim, 1> lambda = cost * state;
// Energy
complex<double> E = state.dot(lambda);
// Back propagation
DMatrix<dim, 1> exp_d0_c = exp_d0.conjugate();
ctrl_amp *= -1;
DMatrix<Dynamic, n_ctrl> out = DMatrix<Dynamic, n_ctrl>::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<complex<double>, Eigen::Matrix<double, Dynamic, n_ctrl>>(
E,
2*out.imag()
);
};
DMatrix<dim, dim> get_evolution(DMatrix<Dynamic, n_ctrl> ctrl_amp,
double dt) {
size_t steps = ctrl_amp.rows();
Eigen::Array<complex<double>, dim, 1> exp_d0 = (d0*dt).exp();
ctrl_amp *= dt;
DMatrix<dim, dim> u = (DMatrix<dim, dim>)u0_inverse;
u = u.array().colwise() * exp_d0;
for (size_t j = 0; j < length; j++) {
u = us[j] * u;
u = u.array().colwise() * (ds[j]*ctrl_amp(0, j)).exp();
}
for (size_t i = 1; i < steps; i++) {
u = u0_inverse_u_last * u;
u = u.array().colwise() * exp_d0;
for (size_t j = 0; j < length; j++) {
u = us[j] * u;
u = u.array().colwise() * (ds[j]*ctrl_amp(i, j)).exp();
}
}
u = us[length] * u;
return u;
};
double evolved_gate_infidelity(DMatrix<Dynamic, n_ctrl> ctrl_amp,
double dt,
DMatrix<dim, dim> target) {
DMatrix<dim, dim> U = get_evolution(ctrl_amp, dt);
return unitary_gate_infidelity(U, target);
};
std::tuple<double, Eigen::Matrix<double, Dynamic, n_ctrl>>
gate_switching_function(DMatrix<Dynamic, n_ctrl> ctrl_amp,
double dt,
DMatrix<dim, dim> target) {
// forward propagation
size_t steps = ctrl_amp.rows();
Eigen::Array<complex<double>, dim, 1> exp_d0 = (d0*dt).exp();
ctrl_amp *= dt;
DMatrix<dim, dim> u = (DMatrix<dim, dim>)u0_inverse;
u = u.array().colwise() * exp_d0;
for (size_t j = 0; j < length; j++) {
u = us[j] * u;
u = u.array().colwise() * (ds[j]*ctrl_amp(0, j)).exp();
}
for (size_t i = 1; i < steps; i++) {
u = u0_inverse_u_last * u;
u = u.array().colwise() * exp_d0;
for (size_t j = 0; j < length; j++) {
u = us[j] * u;
u = u.array().colwise() * (ds[j]*ctrl_amp(i, j)).exp();
}
}
u = us[length] * u;
// Energy
complex<double> F = std::conj((target.adjoint()*u).trace());
// Back propagation
Eigen::Array<complex<double>, dim, 1> exp_d0_c = exp_d0.conjugate();
ctrl_amp *= -1;
DMatrix<Dynamic, n_ctrl> out = DMatrix<Dynamic, n_ctrl>::Zero(steps,
length);
for (size_t k = steps-1; true;) {
for (size_t j = length-1; true;) {
out(k, j) = (target.adjoint()*hs[j]*u).trace();
u = us_inverse_individual[j] * u;
u = u.array().colwise() * (ds[j] * ctrl_amp(k, j)).exp();
u = us_individual[j] * u;
target = us_inverse_individual[j] * target;
target = target.array().colwise()
* (ds[j] * ctrl_amp(k, j)).exp();
target = us_individual[j] * target;
if (j == 0) {
break;
}
j--;
}
if (k == 0) {
break;
}
u = u0_inverse * u;
u = u.array().colwise() * exp_d0_c;
u = u0 * u;
target = u0_inverse * target;
target = target.array().colwise() * exp_d0_c;
target = u0 * target;
k--;
}
Eigen::Index d = target.rows();
double normalisation = 1.0/(d*(d+1));
return std::tuple<double, Eigen::Matrix<double, Dynamic, n_ctrl>>(
1-normalisation*(std::pow(std::abs(F), 2)+d),
-2*normalisation*(F*out).imag()
);
};
};
}