Commit 12ddccea authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

WIP for QITE



Now had a clearer picture about the algorithm execution.

Still missing a few components.

Signed-off-by: Nguyen, Thien Minh's avatarThien Nguyen <nguyentm@ornl.gov>
parent 5c708e42
......@@ -26,6 +26,10 @@ namespace xacc {
namespace algorithm {
bool QITE::initialize(const HeterogeneousMap &parameters)
{
// TEMP CODE:
m_nbSteps = 1;
m_accelerator = xacc::getAccelerator("qpp");
// TODO
return true;
}
......@@ -88,10 +92,77 @@ std::shared_ptr<CompositeInstruction> QITE::constructPropagateCircuit() const
void QITE::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const
{
// Helper to generate all permutation of Pauli observables:
// e.g.
// 1-qubit: I, X, Y, Z
// 2-qubit: II, IX, IY, IZ, XI, XX, XY, XZ, YI, YX, YY, YZ, ZI, ZX, ZY, ZZ
const auto generatePauliPermutation = [](int in_nbQubits) -> std::vector<std::string> {
assert(in_nbQubits > 0);
const int nbPermutations = std::pow(4, in_nbQubits);
std::vector<std::string> opsList;
opsList.reserve(nbPermutations);
const std::vector<std::string> pauliOps { "X", "Y", "Z" };
const auto addQubitPauli = [&opsList, &pauliOps](int in_qubitIdx){
const auto currentOpListSize = opsList.size();
for (int i = 0; i < currentOpListSize; ++i)
{
auto& currentOp = opsList[i];
for (const auto& pauliOp : pauliOps)
{
const auto newOp = currentOp + pauliOp + std::to_string(in_qubitIdx);
opsList.emplace_back(newOp);
}
}
};
opsList = { "", "X0", "Y0", "Z0" };
for (int i = 1; i < in_nbQubits; ++i)
{
addQubitPauli(i);
}
assert(opsList.size() == nbPermutations);
std::sort(opsList.begin(), opsList.end());
return opsList;
};
const auto pauliObsOps = generatePauliPermutation(buffer->size());
const std::string pauliObsStr = [&pauliObsOps](){
std::string result = "1.0 " + pauliObsOps[1];
for (int i = 2; i < pauliObsOps.size(); ++i)
{
result.append(" + 1.0 " + pauliObsOps[i]);
}
return result;
}();
// Calculate approximate A operator observable at each time step.
const auto calcAOps = [&](std::shared_ptr<CompositeInstruction>) -> std::shared_ptr<Observable> {
const auto calcAOps = [&](std::shared_ptr<CompositeInstruction> in_kernel) -> std::shared_ptr<Observable> {
// Step 1: Observe the kernels using the various Pauli
// operators to calculate S and b.
std::vector<double> sigmaExpectation(pauliObsOps.size());
sigmaExpectation[0] = 1.0;
for (int i = 1; i < pauliObsOps.size(); ++i)
{
std::shared_ptr<Observable> tomoObservable = std::make_shared<xacc::quantum::PauliOperator>();
const std::string pauliObsStr = "1.0 " + pauliObsOps[i];
// std::cout << "Observable string: \n" << pauliObsStr << "\n";
tomoObservable->fromString(pauliObsStr);
std::cout << "Observable: \n" << tomoObservable->toString() << "\n";
assert(tomoObservable->getSubTerms().size() == 1);
assert(tomoObservable->getNonIdentitySubTerms().size() == 1);
auto obsKernel = tomoObservable->observe(in_kernel).front();
// std::cout << "HOWDY:\n" << obsKernel->toString() << "\n";
auto tmpBuffer = xacc::qalloc(buffer->size());
m_accelerator->execute(tmpBuffer, obsKernel);
const auto expval = tmpBuffer->getExpectationValueZ();
// std::cout << "Exp-Val = " << expval << "\n";
sigmaExpectation[i] = expval;
}
// TODO: this requires some Pauli algebra computation.
// Step 2: Calculate S matrix and b vector
// i.e. set up the linear equation Sa = b
......@@ -99,10 +170,59 @@ void QITE::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const
// i.e. set-up the observables to calculate those entries.
// TODO: construct circuits and evaluate to get expectation values
// and populate S matrix and b vector.
Eigen::MatrixXf S_Mat;
Eigen::VectorXf b_Vec;
const auto sMatDim = pauliObsOps.size();
Eigen::MatrixXcf S_Mat = Eigen::MatrixXcf::Zero(sMatDim, sMatDim);
Eigen::VectorXcf b_Vec = Eigen::VectorXcf::Zero(sMatDim);
// const auto a_Vec = S_Mat.bdcSvd(ComputeThinU | ComputeThinV).solve(b_Vec);
const auto calcSmatEntry = [](const std::vector<double>& in_tomoExp, int in_row, int in_col) -> std::complex<double> {
// Map the tomography expectation to the S matrix
// S(i, j) = <psi|sigma_dagger(i)sigma(j)|psi>
// sigma_dagger(i)sigma(j) will produce another Pauli operator with an additional coefficient.
// e.g. sigma_x * sigma_y = i*sigma_z
// TODO: formalize this, for testing, we do 1-qubit here.
// For multiple qubits, use this one-qubit base map to generate the mapping.
assert(in_tomoExp.size() == 4);
int indexMap[4][4] = {
{0, 1, 2, 3},
{1, 0, 3, 2},
{2, 3, 0, 1},
{3, 2, 1, 0}
};
const std::complex<double> I{ 0.0, 1.0};
std::complex<double> coefficientMap [4][4] = {
{1, 1, 1, 1},
{1, 1, I, -I},
{1, -I, 1, I},
{1, I, -I, 1}
};
return in_tomoExp[indexMap[in_row][in_col]]*coefficientMap[in_row][in_col];
};
// S matrix:
// S(i, j) = <psi|sigma_dagger(i)sigma(j)|psi>
for (int i = 0; i < sMatDim; ++i)
{
for (int j = 0; j < sMatDim; ++j)
{
S_Mat(i, j) = calcSmatEntry(sigmaExpectation, i, j);
}
}
// b vector:
// Project/flatten the target observable into the full list of all
// possible Pauli operator combinations.
// e.g. H = a X + b Z (1 qubit)
// -> { 0.0, a, 0.0, b } (the ordering is I, X, Y, Z)
std::vector<std::complex<double>> obsProjCoeffs (sMatDim);
// TODO: assign this vector
// !! This is complex!!!
auto lhs = S_Mat + S_Mat.transpose();
auto rhs = -b_Vec;
const auto a_Vec = lhs.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(rhs);
// TODO: construct A observable from the coefficients in a_Vec
return nullptr;
};
......
......@@ -36,6 +36,8 @@ private:
int m_nbSteps;
// dBeta, i.e. step size
double m_dBeta;
// Accelerator
std::shared_ptr<Accelerator> m_accelerator;
// Hamiltonian Observable, i.e. H = Sum(h_i)
Observable* m_observable;
// Ansatz circuit (apply before Trotter steps)
......
......@@ -21,7 +21,10 @@
TEST(QITETester, checkSimple)
{
auto buffer = xacc::qalloc(1);
auto qite = xacc::getService<xacc::Algorithm>("qite");
qite->initialize({});
qite->execute(buffer);
}
int main(int argc, char **argv) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment