Commit 6fed858d authored by Nguyen, Thien Minh's avatar Nguyen, Thien Minh
Browse files

Debug IQPE implementation



- Add a global phase rotation for the identity term.

- Updated the example for testing.

Needs to figure out converting the observable to the canonical weighted pauli form.

Signed-off-by: default avatarThien Nguyen <nguyentm@ornl.gov>
parent 74030040
Loading
Loading
Loading
Loading
+19 −7
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@ Ansatz TrotterEvolution::create_ansatz(Observable *obs,
  if (params.keyExists<double>("dt")) {
    dt = params.get<double>("dt");
  }

  // Just use exp_i_theta for now
  // TODO: formalize a standard library kernel for this.
  auto expCirc = std::dynamic_pointer_cast<xacc::quantum::Circuit>(
@@ -130,7 +129,6 @@ bool IterativeQpeWorkflow::initialize(const HeterogeneousMap &params) {
  if (params.keyExists<int>("iterations")) {
    num_iters = params.get<int>("iterations");
  }

  return (num_steps >= 1) && (num_iters >= 1);
}

@@ -164,14 +162,27 @@ IterativeQpeWorkflow::constructQpeCircuit(const QuantumSimulationModel &model,

  // Apply C-U^n
  int power = 1 << (k - 1);
  // std::cout << "Power = " << power << "\n"; 
  for (int i = 0; i < power; ++i) {
    for (int j = 0; j < num_steps; ++j) {
      for (int instId = 0; instId < ctrlKernel->nInstructions(); ++instId) {
        // We need to clone the instruction since it'll be repeated.
        kernel->addInstruction(ctrlKernel->getInstruction(instId)->clone());
      }
    }
  }

  // Rz on ancilla qubit
  // Global phase due to identity pauli
  if (model.observable->getIdentitySubTerm()) {
    const double idCoeff =
        model.observable->getIdentitySubTerm()->coefficient().real();
    const double globalPhase = 2 * M_PI * idCoeff * power;
    // std::cout << "Global phase = " << globalPhase << "\n";
    kernel->addInstruction(
        provider->createInstruction("Rz", {ancBit}, {globalPhase}));
  }

  kernel->addInstruction(provider->createInstruction("Rz", {ancBit}, {omega}));

  // Hadamard on ancilla qubit
@@ -232,12 +243,13 @@ IterativeQpeWorkflow::execute(const QuantumSimulationModel &model) {
      }
    }();
    
    std::cout << "Iter " << iterIdx << ": Result = " << bitResult << "\n";
    if (bitResult) {
      omega_coef = omega_coef + 0.5;
    }
    // std::cout << "Iter " << iterIdx << ": Result = " << bitResult << "; omega_coef = " << omega_coef << "\n";

  }
  std::cout << "Final phase = " << omega_coef << "\n";
  // std::cout << "Final phase = " << omega_coef << "\n";
  return { {"phase", omega_coef}};
}

+12 −11
Original line number Diff line number Diff line
@@ -6,25 +6,26 @@
// Compile and run with:
/// $ qcor -qpu qpp IterativeQpeWorkflow.cpp
/// $ ./a.out

// Ansatz to bring the state into an eigenvector state of the Hamiltonian.
__qpu__ void eigen_state_prep(qreg q) {
  auto theta = 0.297113;
  X(q[0]);
  auto exponent_op = X(0) * Y(1) - Y(0) * X(1);
  exp_i_theta(q, theta, exponent_op);
  using qcor::openqasm;
  u3(pi / 4, 0, 0) q[0];
}

int main(int argc, char **argv) {
  // Create Hamiltonian
  auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.143 * Y(0) * Y(1) + 0.21829 * Z(0) -
           6.125 * Z(1);
  // Create Hamiltonian:
  // Important: this must be a weighted pauli operator list.
  // TODO: add function to convert arbitrary Hamiltonian to the weighted form.
  auto H = 0.5 + 0.25 * X(0) + 0.25 * Z(0);
  auto problemModel =
      qsim::ModelBuilder::createModel(eigen_state_prep, H, 2, 0);
      qsim::ModelBuilder::createModel(eigen_state_prep, H, 1, 0);

  // Instantiate an IQPE workflow.
  auto workflow = qsim::getWorkflow("iqpe", {{"iterations", 8}});
  auto workflow =
      qsim::getWorkflow("iqpe", {{"time-steps", 4}, {"iterations", 4}});

  // Result should contain the observable expectation value along Trotter steps.
  auto result = workflow->execute(problemModel);
  const double phaseValue = result.get<double>("phase");
  std::cout << "Final phase = " << phaseValue << "\n";
  return 0;
}
 No newline at end of file