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

Initial set-up for some additional circuit optimization routines


Signed-off-by: Nguyen, Thien Minh's avatarThien Nguyen <nguyentm@ornl.gov>
parent 1d385171
......@@ -13,7 +13,7 @@
set (LIBRARY_NAME xacc-circuit-optimizers)
file (GLOB_RECURSE HEADERS *.hpp)
file (GLOB SRC simple/*.cpp OptimizersActivator.cpp pulse/*.cpp)
file (GLOB SRC simple/*.cpp OptimizersActivator.cpp pulse/*.cpp gate_merge/*.cpp)
# Set up dependencies to resources to track changes
usFunctionGetResourceSource(TARGET ${LIBRARY_NAME} OUT SRC)
......@@ -39,7 +39,7 @@ usFunctionEmbedResources(TARGET ${LIBRARY_NAME}
manifest.json
)
target_include_directories(${LIBRARY_NAME} PUBLIC simple pulse ${CMAKE_SOURCE_DIR}/tpls/eigen ${CMAKE_SOURCE_DIR}/tpls/exprtk)
target_include_directories(${LIBRARY_NAME} PUBLIC simple pulse gate_merge ${CMAKE_SOURCE_DIR}/tpls/eigen ${CMAKE_SOURCE_DIR}/tpls/exprtk)
target_link_libraries(${LIBRARY_NAME} xacc xacc-quantum-gate)
if(APPLE)
......@@ -56,5 +56,6 @@ install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins)
if(XACC_BUILD_TESTS)
add_subdirectory(simple/tests)
add_subdirectory(pulse/tests)
add_subdirectory(gate_merge/tests)
endif()
......@@ -12,12 +12,12 @@
*******************************************************************************/
#include "CircuitOptimizer.hpp"
#include "default_placement.hpp"
#include "GateMergeOptimizer.hpp"
#include "PulseTransform.hpp"
#include "GateFusion.hpp"
#include "cppmicroservices/BundleActivator.h"
#include "cppmicroservices/BundleContext.h"
#include "cppmicroservices/ServiceProperties.h"
#include <memory>
#include <set>
......@@ -45,6 +45,8 @@ public:
context.RegisterService<xacc::IRTransformation>(std::make_shared<xacc::quantum::PulseTransform>());
context.RegisterService<GateFuser>(std::make_shared<GateFuser>());
context.RegisterService<xacc::IRTransformation>(std::make_shared<xacc::quantum::MergeSingleQubitGatesOptimizer>());
context.RegisterService<xacc::IRTransformation>(std::make_shared<xacc::quantum::MergeTwoQubitBlockOptimizer>());
}
/**
......
#include "GateMergeOptimizer.hpp"
#include <cassert>
namespace xacc {
namespace quantum {
void MergeSingleQubitGatesOptimizer::apply(std::shared_ptr<CompositeInstruction> program, const std::shared_ptr<Accelerator> accelerator, const HeterogeneousMap &options)
{
std::set<size_t> processInstIdx;
for (size_t instIdx = 0; instIdx < program->nInstructions(); ++instIdx)
{
const auto sequence = findSingleQubitGateSequence(program, instIdx, 2, processInstIdx);
if (!sequence.empty())
{
for (const auto& instIdx: sequence)
{
assert(!xacc::container::contains(processInstIdx, instIdx));
processInstIdx.emplace(instIdx);
}
// std::cout << "Found sequence:\n";
// for (const auto& idx : sequence)
// {
// std::cout << program->getInstruction(idx)->toString() << "\n";
// }
}
}
}
std::vector<size_t> MergeSingleQubitGatesOptimizer::findSingleQubitGateSequence(const std::shared_ptr<CompositeInstruction> in_program, size_t in_startIdx, size_t in_lengthLimit, const std::set<size_t>& in_processedInstIdx) const
{
const auto nbInstructions = in_program->nInstructions();
std::unordered_map<size_t, std::vector<size_t>> qubitToSequence;
for (size_t instIdx = in_startIdx; instIdx < nbInstructions; ++instIdx)
{
auto instPtr = in_program->getInstruction(instIdx);
if (instPtr->bits().size() > 1)
{
// Two-qubit gate: clear the sequence of all qubit operands.
// Returns if any sequence meets the length.
auto& seq1 = qubitToSequence[instPtr->bits()[0]];
auto& seq2 = qubitToSequence[instPtr->bits()[1]];
// Returns if a sequence has been accumulated.
if (seq1.size() >= in_lengthLimit || seq2.size() >= in_lengthLimit)
{
if (seq1.size() >= in_lengthLimit && seq2.size() >= in_lengthLimit)
{
assert(seq1[0] != seq2[0]);
return (seq1[0] < seq2[0]) ? seq1 : seq2;
}
return (seq1.size() >= in_lengthLimit) ? seq1 : seq2;
}
seq1.clear();
seq2.clear();
}
else
{
if (instPtr->name() == "Measure")
{
if (qubitToSequence[instPtr->bits()[0]].size() >= in_lengthLimit)
{
return qubitToSequence[instPtr->bits()[0]];
}
qubitToSequence[instPtr->bits()[0]].clear();
}
else
{
// If this single-qubit gate has not been covered before.
if (!xacc::container::contains(in_processedInstIdx, instIdx))
{
// Single-qubit gate: accumulate the sequence.
auto& currentSeq = qubitToSequence[instPtr->bits()[0]];
currentSeq.emplace_back(instIdx);
}
}
}
}
// Handle multiple un-terminated long sequence.
size_t minInstIdx = in_program->nInstructions();
for (const auto& [qIdx, seq]: qubitToSequence)
{
if (seq.size() >= in_lengthLimit)
{
minInstIdx = (seq[0] < minInstIdx) ? seq[0] : minInstIdx;
}
}
for (const auto& [qIdx, seq]: qubitToSequence)
{
if (seq.size() >= in_lengthLimit && seq[0] == minInstIdx)
{
return seq;
}
}
return {};
}
}
}
\ No newline at end of file
#pragma once
#include "IRTransformation.hpp"
namespace xacc {
namespace quantum {
// Merge contiguous sequence of gates (1- or 2-qubit)
// into a more efficient gate sequence.
class MergeSingleQubitGatesOptimizer : public IRTransformation
{
public:
virtual void apply(std::shared_ptr<CompositeInstruction> program,
const std::shared_ptr<Accelerator> accelerator,
const HeterogeneousMap &options = {}) override;
virtual const IRTransformationType type() const override { return IRTransformationType::Optimization; }
const std::string name() const override { return "single-qubit-gate-merging"; }
const std::string description() const override { return ""; }
private:
std::vector<size_t> findSingleQubitGateSequence(const std::shared_ptr<CompositeInstruction> in_program, size_t in_startIdx, size_t in_lengthLimit, const std::set<size_t>& in_processedInstIdx) const;
};
// Try to merge a block containing single and two-qubit gates
// and decompose it into a more optimized representation only if *possible*.
// e.g. only if the original block has more gates than its re-synthesized version.
// We could also define a custom target for re-write
// such as reducing the number of two-qubit gates in the block
// rather than the overall gate count.
class MergeTwoQubitBlockOptimizer : public IRTransformation
{
public:
virtual void apply(std::shared_ptr<CompositeInstruction> program,
const std::shared_ptr<Accelerator> accelerator,
const HeterogeneousMap &options = {}) override { /* TODO */ };
virtual const IRTransformationType type() const override { return IRTransformationType::Optimization; }
const std::string name() const override { return "two-qubit-block-merging"; }
const std::string description() const override { return ""; }
};
}
}
\ No newline at end of file
add_xacc_test(GateMerging)
target_link_libraries(GateMergingTester xacc-quantum-gate)
\ No newline at end of file
#include <gtest/gtest.h>
#include "xacc.hpp"
#include "xacc_service.hpp"
#include "IRTransformation.hpp"
TEST(GateMergingTester, checkSingleQubitSimple)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto f = c->compile(R"(__qpu__ void test1(qbit q) {
Z(q[0]);
H(q[0]);
X(q[0]);
H(q[0]);
})")->getComposites()[0];
auto opt = xacc::getService<xacc::IRTransformation>("single-qubit-gate-merging");
opt->apply(f, nullptr);
}
TEST(GateMergingTester, checkSingleQubitStopAtTwoQubitGate)
{
auto c = xacc::getService<xacc::Compiler>("xasm");
auto f = c->compile(R"(__qpu__ void test2(qbit q) {
H(q[0]);
X(q[0]);
H(q[0]);
CNOT(q[0], q[1]);
H(q[0]);
})")->getComposites()[0];
auto opt = xacc::getService<xacc::IRTransformation>("single-qubit-gate-merging");
opt->apply(f, nullptr);
}
int main(int argc, char **argv) {
xacc::Initialize(argc, argv);
::testing::InitGoogleTest(&argc, argv);
auto ret = RUN_ALL_TESTS();
xacc::Finalize();
return ret;
}
\ No newline at end of file
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