Commit 9ac4b78b authored by Nguyen, Thien's avatar Nguyen, Thien
Browse files

Fixed exp-val-z calculation for the Qpp Accelerator



Swapping the order of conditional check so that in we can further optimize for the case where there is no If statements in the circuit nor shots; in that case, calculate expectation analytically.

Also, fixed a potential bug whereby the shots count may not be reset if using the accelerator multiple times.
Signed-off-by: Nguyen, Thien's avatarThien Nguyen <nguyentm@ornl.gov>
parent 996f6bb1
...@@ -181,6 +181,8 @@ namespace quantum { ...@@ -181,6 +181,8 @@ namespace quantum {
void QppAccelerator::initialize(const HeterogeneousMap& params) void QppAccelerator::initialize(const HeterogeneousMap& params)
{ {
m_visitor = std::make_shared<QppVisitor>(); m_visitor = std::make_shared<QppVisitor>();
// Default: no shots (unless otherwise specified)
m_shots = -1;
if (params.keyExists<int>("shots")) if (params.keyExists<int>("shots"))
{ {
m_shots = params.get<int>("shots"); m_shots = params.get<int>("shots");
...@@ -210,57 +212,63 @@ namespace quantum { ...@@ -210,57 +212,63 @@ namespace quantum {
m_visitor->finalize(); m_visitor->finalize();
}; };
// Not possible to simulate shot count by direct sampling,
if (m_shots < 0) // e.g. must collapse the state vector.
{ if(!shotCountFromFinalStateVec(compositeInstruction))
runCircuit(false);
}
else
{ {
// Not possible to simulate shot count by direct sampling, if (m_shots < 0)
// e.g. must collapse the state vector. {
if(!shotCountFromFinalStateVec(compositeInstruction)) runCircuit(false);
{ }
else
{
for (int i = 0; i < m_shots; ++i) for (int i = 0; i < m_shots; ++i)
{ {
runCircuit(true); runCircuit(true);
} }
} }
else }
{ else
// Index of measure bits {
std::vector<size_t> measureBitIdxs; // Index of measure bits
m_visitor->initialize(buffer); std::vector<size_t> measureBitIdxs;
// Walk the IR tree, and visit each node m_visitor->initialize(buffer);
InstructionIterator it(compositeInstruction); // Walk the IR tree, and visit each node
while (it.hasNext()) InstructionIterator it(compositeInstruction);
while (it.hasNext())
{
auto nextInst = it.next();
if (nextInst->isEnabled())
{ {
auto nextInst = it.next(); if (!isMeasureGate(nextInst))
if (nextInst->isEnabled())
{ {
if (!isMeasureGate(nextInst)) nextInst->accept(m_visitor);
{ }
nextInst->accept(m_visitor); else
} {
else // Just collect the indices of measured qubit
{ measureBitIdxs.emplace_back(nextInst->bits()[0]);
// Just collect the indices of measured qubit
measureBitIdxs.emplace_back(nextInst->bits()[0]);
}
} }
} }
}
// Run bit-string simulation
if (!measureBitIdxs.empty()) // Run bit-string simulation
if (!measureBitIdxs.empty())
{
const auto& stateVec = m_visitor->getStateVec();
if (m_shots < 0)
{
const double expectedValueZ = QppVisitor::calcExpectationValueZ(stateVec, measureBitIdxs);
buffer->addExtraInfo("exp-val-z", expectedValueZ);
}
else
{ {
const auto& stateVec = m_visitor->getStateVec();
// Try multi-threaded execution if there are many shots. // Try multi-threaded execution if there are many shots.
const bool multiThreadEnabled = (m_shots > 1024); const bool multiThreadEnabled = (m_shots > 1024);
generateMeasureBitString(buffer, measureBitIdxs, stateVec, m_shots, multiThreadEnabled); generateMeasureBitString(buffer, measureBitIdxs, stateVec, m_shots, multiThreadEnabled);
} }
}
m_visitor->finalize(); m_visitor->finalize();
}
} }
} }
......
...@@ -72,7 +72,7 @@ namespace quantum { ...@@ -72,7 +72,7 @@ namespace quantum {
return m_buffer->size() - in_idx - 1; return m_buffer->size() - in_idx - 1;
} }
double QppVisitor::calcExpectationValueZ() const double QppVisitor::calcExpectationValueZ(const KetVectorType& in_stateVec, const std::vector<qpp::idx>& in_bits)
{ {
const auto hasEvenParity = [](size_t x, const std::vector<size_t>& in_qubitIndices) -> bool { const auto hasEvenParity = [](size_t x, const std::vector<size_t>& in_qubitIndices) -> bool {
size_t count = 0; size_t count = 0;
...@@ -88,9 +88,9 @@ namespace quantum { ...@@ -88,9 +88,9 @@ namespace quantum {
double result = 0.0; double result = 0.0;
for(uint64_t i = 0; i < m_stateVec.size(); ++i) for(uint64_t i = 0; i < in_stateVec.size(); ++i)
{ {
result += (hasEvenParity(i, m_measureBits) ? 1.0 : -1.0) * std::norm(m_stateVec[i]); result += (hasEvenParity(i, in_bits) ? 1.0 : -1.0) * std::norm(in_stateVec[i]);
} }
return result; return result;
...@@ -270,7 +270,7 @@ namespace quantum { ...@@ -270,7 +270,7 @@ namespace quantum {
if (!m_shotsMode) if (!m_shotsMode)
{ {
// Not running a shot simulation, calculate the expectation value. // Not running a shot simulation, calculate the expectation value.
const double expectedValueZ = calcExpectationValueZ(); const double expectedValueZ = calcExpectationValueZ(m_stateVec, m_measureBits);
m_buffer->addExtraInfo("exp-val-z", expectedValueZ); m_buffer->addExtraInfo("exp-val-z", expectedValueZ);
} }
else else
......
...@@ -55,9 +55,9 @@ public: ...@@ -55,9 +55,9 @@ public:
virtual std::shared_ptr<QppVisitor> clone() { return std::make_shared<QppVisitor>(); } virtual std::shared_ptr<QppVisitor> clone() { return std::make_shared<QppVisitor>(); }
const KetVectorType& getStateVec() const { return m_stateVec; } const KetVectorType& getStateVec() const { return m_stateVec; }
static double calcExpectationValueZ(const KetVectorType& in_stateVec, const std::vector<qpp::idx>& in_bits);
private: private:
qpp::idx xaccIdxToQppIdx(size_t in_idx) const; qpp::idx xaccIdxToQppIdx(size_t in_idx) const;
double calcExpectationValueZ() const;
private: private:
std::shared_ptr<AcceleratorBuffer> m_buffer; std::shared_ptr<AcceleratorBuffer> m_buffer;
std::vector<qpp::idx> m_dims; std::vector<qpp::idx> m_dims;
......
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