Commit c8454c66 authored by Nguyen, Thien's avatar Nguyen, Thien

Tidy up the impl and add observable unit tests

Signed-off-by: Nguyen, Thien's avatarThien Nguyen <nguyentm@ornl.gov>
parent a4744493
......@@ -34,8 +34,29 @@ getBaseLength(const std::shared_ptr<xacc::CompositeInstruction> &in_composite) {
}
}
return length;
};
}
bool compareInst(xacc::InstPtr in_a, xacc::InstPtr in_b) {
if (!in_a || !in_b) {
return false;
}
// We should only compare elementary instructions.
assert(!in_a->isComposite() && !in_b->isComposite());
assert(in_a->isEnabled() && in_b->isEnabled());
return (in_a->name() == in_b->name()) && (in_a->bits() == in_b->bits()) &&
(in_a->getParameters() == in_b->getParameters());
}
// Helper to pop the instruction stack (so that we can walk both trees
// simultaneously)
xacc::InstPtr getNextInstruction(xacc::InstructionIterator &iter) {
while (iter.hasNext()) {
auto nextInst = iter.next();
if (nextInst->isEnabled() && !nextInst->isComposite()) {
return nextInst;
}
}
return nullptr;
}
} // namespace
namespace xacc {
namespace quantum {
......@@ -80,31 +101,8 @@ ObservedAnsatz ObservedAnsatz::fromObservedComposites(
InstructionIterator &out_Iter) {
assert(getBaseLength(in_base) <= getBaseLength(in_toTest));
bool result = true;
InstructionIterator baseIt(in_base);
InstructionIterator otherIter(in_toTest);
// Helper to pop the instruction stack (so that we can walk both trees
// simultaneously)
const auto getNextInstruction =
[](InstructionIterator &iter) -> InstPtr {
while (iter.hasNext()) {
auto nextInst = iter.next();
if (nextInst->isEnabled() && !nextInst->isComposite()) {
return nextInst;
}
}
return nullptr;
};
const auto compareInst = [](InstPtr in_a, InstPtr in_b) -> bool {
if (!in_a || !in_b) {
return false;
}
// We should only compare elementary instructions.
assert(!in_a->isComposite() && !in_b->isComposite());
assert(in_a->isEnabled() && in_b->isEnabled());
return in_a->toString() == in_b->toString();
};
while (baseIt.hasNext()) {
auto nextInst = baseIt.next();
if (nextInst->isEnabled() && !nextInst->isComposite()) {
......@@ -193,6 +191,46 @@ ObservedAnsatz ObservedAnsatz::fromObservedComposites(
result.m_obsCircuits = in_composites;
return result;
}
bool ObservedAnsatz::validate(
const std::vector<std::shared_ptr<CompositeInstruction>> &in_composites)
const {
if (m_obsCircuits.size() != in_composites.size()) {
return false;
}
auto gateRegistry = xacc::getService<xacc::IRProvider>("quantum");
for (int i = 0; i < m_obsCircuits.size(); ++i) {
auto obsCirc = m_obsCircuits[i];
std::shared_ptr<xacc::CompositeInstruction> combinedComp =
gateRegistry->createComposite("__RECOVERED__" + std::to_string(i));
for (int idx = 0; idx < m_baseAnsatz->nInstructions(); ++idx) {
combinedComp->addInstruction(m_baseAnsatz->getInstruction(idx)->clone());
}
for (int idx = 0; idx < obsCirc->nInstructions(); ++idx) {
combinedComp->addInstruction(obsCirc->getInstruction(idx)->clone());
}
auto originalCirc = in_composites[i];
// Compare two composites:
InstructionIterator origIter(originalCirc);
InstructionIterator otherIter(combinedComp);
while (origIter.hasNext()) {
auto nextInst = origIter.next();
if (nextInst->isEnabled() && !nextInst->isComposite()) {
// Pop the other iter as well
auto otherInstr = getNextInstruction(otherIter);
if (!compareInst(nextInst, otherInstr)) {
return false;
}
}
}
assert(!origIter.hasNext());
if (otherIter.hasNext()) {
// The other composite contains extra instructions.
return false;
}
}
return true;
}
} // namespace quantum
} // namespace xacc
\ No newline at end of file
......@@ -30,6 +30,9 @@ public:
getObservedSubCircuits() const {
return m_obsCircuits;
}
// Helper for users to verify that the decomposition indeed valid
bool validate(const std::vector<std::shared_ptr<CompositeInstruction>>
&in_composites) const;
private:
std::shared_ptr<CompositeInstruction> m_baseAnsatz;
......
......@@ -6,6 +6,7 @@
#include <random>
#include <iterator>
#include "IRUtils.hpp"
#include "xacc_observable.hpp"
using namespace xacc::quantum;
......@@ -61,24 +62,57 @@ TEST(IRUtilsTester, checkSimple) {
std::cout << "HOWDY: \n" << circ->toString() << "\n";
}
auto result = ObservedAnsatz::fromObservedComposites(testCircs);
EXPECT_EQ(result.getBase()->nInstructions(), base->nInstructions());
EXPECT_EQ(result.getBase()->toString(), base->toString());
for (int i = 0; i < result.getObservedSubCircuits().size(); ++i) {
auto circ = result.getObservedSubCircuits()[i];
// All circuits have one extra gate and a Measure
EXPECT_EQ(circ->nInstructions(), 2);
std::shared_ptr<xacc::CompositeInstruction> newComp =
gateRegistry->createComposite("__RECOVERED__" + std::to_string(i));
for (int idx = 0; idx < result.getBase()->nInstructions(); ++idx) {
newComp->addInstruction(result.getBase()->getInstruction(idx)->clone());
}
for (int idx = 0; idx < circ->nInstructions(); ++idx) {
newComp->addInstruction(circ->getInstruction(idx)->clone());
}
auto originalCirc = testCircs[i];
// The recovered: base + obs sub-circuit matches the original
EXPECT_EQ(newComp->toString(), originalCirc->toString());
EXPECT_TRUE(result.validate(testCircs));
}
TEST(IRUtilsTester, checkObservable) {
{
auto H_N_2 = xacc::quantum::getObservable(
"pauli", std::string("5.907 - 2.1433 X0X1 "
"- 2.1433 Y0Y1"
"+ .21829 Z0 - 6.125 Z1"));
xacc::qasm(R"(
.compiler xasm
.circuit deuteron_ansatz
.parameters theta
.qbit q
X(q[0]);
Ry(q[1], theta);
CNOT(q[1],q[0]);
)");
auto ansatz = xacc::getCompiled("deuteron_ansatz");
auto evaled = ansatz->operator()({1.2345});
const auto fsToExe = H_N_2->observe(evaled);
auto result = ObservedAnsatz::fromObservedComposites(fsToExe);
EXPECT_EQ(result.getBase()->toString(), evaled->toString());
EXPECT_TRUE(result.validate(fsToExe));
}
{
auto H_N_3 = xacc::quantum::getObservable(
"pauli",
std::string(
"5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1 + "
"9.625 - 9.625 Z2 - 3.91 X1 X2 - 3.91 Y1 Y2"));
xacc::qasm(R"(
.compiler xasm
.circuit deuteron_ansatz_h3
.parameters t0, t1
.qbit q
X(q[0]);
exp_i_theta(q, t0, {{"pauli", "X0 Y1 - Y0 X1"}});
exp_i_theta(q, t1, {{"pauli", "X0 Z1 Y2 - X2 Z1 Y0"}});
)");
auto ansatz = xacc::getCompiled("deuteron_ansatz_h3");
auto evaled = ansatz->operator()({1.2345, 6.789});
const auto fsToExe = H_N_3->observe(evaled);
auto result = ObservedAnsatz::fromObservedComposites(fsToExe);
EXPECT_EQ(result.getBase()->toString(), evaled->toString());
EXPECT_TRUE(result.validate(fsToExe));
}
}
......
Markdown is supported
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