Skip to content

Commit

Permalink
Add static indexing to qubitvector norm (Qiskit#178)
Browse files Browse the repository at this point in the history
* add check for diagonal to 1-qubit norm
  • Loading branch information
chriseclectic authored Apr 26, 2019
1 parent fcdd64e commit 5d9b223
Showing 1 changed file with 130 additions and 26 deletions.
156 changes: 130 additions & 26 deletions src/simulators/statevector/qubitvector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1920,51 +1920,148 @@ template <typename data_t>
double QubitVector<data_t>::norm(const reg_t &qubits, const cvector_t &mat) const {

const uint_t N = qubits.size();
const uint_t DIM = BITS[N];

// Error checking
#ifdef DEBUG
check_vector(mat, 2 * N);
#endif

// Lambda function for N-qubit matrix norm
auto lambda = [&](const indexes_t &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < DIM; i++) {
complex_t vi = 0;
for (size_t j = 0; j < DIM; j++)
vi += _mat[i + DIM * j] * data_[inds[j]];
val_re += std::real(vi * std::conj(vi));
// Static array optimized lambda functions
switch (N) {
case 1:
return norm(qubits[0], mat);
case 2: {
// Lambda function for 2-qubit matrix norm
auto lambda = [&](const areg_t<4> &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < 4; i++) {
complex_t vi = 0;
for (size_t j = 0; j < 4; j++)
vi += _mat[i + 4 * j] * data_[inds[j]];
val_re += std::real(vi * std::conj(vi));
}
};
areg_t<2> qubits_arr = {{qubits[0], qubits[1]}};
return std::real(apply_reduction_lambda(lambda, qubits_arr, mat));
}
};
// Use the lambda function
return std::real(apply_reduction_lambda(lambda, qubits, mat));
case 3: {
// Lambda function for 3-qubit matrix norm
auto lambda = [&](const areg_t<8> &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < 8; i++) {
complex_t vi = 0;
for (size_t j = 0; j < 8; j++)
vi += _mat[i + 8 * j] * data_[inds[j]];
val_re += std::real(vi * std::conj(vi));
}
};
areg_t<3> qubits_arr = {{qubits[0], qubits[1], qubits[2]}};
return std::real(apply_reduction_lambda(lambda, qubits_arr, mat));
}
case 4: {
// Lambda function for 4-qubit matrix norm
auto lambda = [&](const areg_t<16> &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < 16; i++) {
complex_t vi = 0;
for (size_t j = 0; j < 16; j++)
vi += _mat[i + 16 * j] * data_[inds[j]];
val_re += std::real(vi * std::conj(vi));
}
};
areg_t<4> qubits_arr = {{qubits[0], qubits[1], qubits[2], qubits[3]}};
return std::real(apply_reduction_lambda(lambda, qubits_arr, mat));
}
default: {
// Lambda function for N-qubit matrix norm
const uint_t DIM = BITS[N];
auto lambda = [&](const indexes_t &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < DIM; i++) {
complex_t vi = 0;
for (size_t j = 0; j < DIM; j++)
vi += _mat[i + DIM * j] * data_[inds[j]];
val_re += std::real(vi * std::conj(vi));
}
};
// Use the lambda function
return std::real(apply_reduction_lambda(lambda, qubits, mat));
}
} // end switch
}

template <typename data_t>
double QubitVector<data_t>::norm_diagonal(const reg_t &qubits, const cvector_t &mat) const {

const uint_t N = qubits.size();
const uint_t DIM = BITS[N];

// Error checking
#ifdef DEBUG
check_vector(mat, N);
#endif

// Lambda function for N-qubit matrix norm
auto lambda = [&](const indexes_t &inds,
const cvector_t &_mat,
double &val_re,
double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < DIM; i++) {
const auto vi = _mat[i] * data_[inds[i]];
val_re += std::real(vi * std::conj(vi));
// Static array optimized lambda functions
switch (N) {
case 1:
return norm_diagonal(qubits[0], mat);
case 2: {
// Lambda function for 2-qubit matrix norm
auto lambda = [&](const areg_t<4> &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < 4; i++) {
const auto vi = _mat[i] * data_[inds[i]];
val_re += std::real(vi * std::conj(vi));
}
};
areg_t<2> qubits_arr = {{qubits[0], qubits[1]}};
return std::real(apply_reduction_lambda(lambda, qubits_arr, mat));
}
};
// Use the lambda function
return std::real(apply_reduction_lambda(lambda, qubits, mat));
case 3: {
// Lambda function for 3-qubit matrix norm
auto lambda = [&](const areg_t<8> &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < 8; i++) {
const auto vi = _mat[i] * data_[inds[i]];
val_re += std::real(vi * std::conj(vi));
}
};
areg_t<3> qubits_arr = {{qubits[0], qubits[1], qubits[2]}};
return std::real(apply_reduction_lambda(lambda, qubits_arr, mat));
}
case 4: {
// Lambda function for 4-qubit matrix norm
auto lambda = [&](const areg_t<16> &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < 16; i++) {
const auto vi = _mat[i] * data_[inds[i]];
val_re += std::real(vi * std::conj(vi));
}
};
areg_t<4> qubits_arr = {{qubits[0], qubits[1], qubits[2], qubits[3]}};
return std::real(apply_reduction_lambda(lambda, qubits_arr, mat));
}
default: {
// Lambda function for N-qubit matrix norm
const uint_t DIM = BITS[N];
auto lambda = [&](const indexes_t &inds, const cvector_t &_mat,
double &val_re, double &val_im)->void {
(void)val_im; // unused
for (size_t i = 0; i < DIM; i++) {
const auto vi = _mat[i] * data_[inds[i]];
val_re += std::real(vi * std::conj(vi));
}
};
// Use the lambda function
return std::real(apply_reduction_lambda(lambda, qubits, mat));
}
} // end switch
}

//------------------------------------------------------------------------------
Expand All @@ -1976,6 +2073,13 @@ double QubitVector<data_t>::norm(const uint_t qubit, const cvector_t &mat) const
#ifdef DEBUG
check_vector(mat, 2);
#endif

// Check if input matrix is diagonal, and if so use diagonal function.
if (mat[1] == 0.0 && mat[2] == 0.0) {
const cvector_t diag = {{mat[0], mat[3]}};
return norm_diagonal(qubit, diag);
}

// Lambda function for norm reduction to real value.
auto lambda = [&](const areg_t<2> &inds,
const cvector_t &_mat,
Expand Down

0 comments on commit 5d9b223

Please sign in to comment.