Unverified Commit 6cc4bf0a authored by Mccaskey, Alex's avatar Mccaskey, Alex Committed by GitHub
Browse files

Merge pull request #44 from tnguyen-ornl/tnguyen/qsim-examples

Qsim code clean-up and reorg
parents 874b7474 270c0d00
Pipeline #123193 passed with stages
in 67 minutes and 3 seconds
......@@ -17,4 +17,7 @@ add_test(NAME qrt_ftqc_qec COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE
add_test(NAME qrt_ftqc_deuteron COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/deuteron.cpp)
add_test(NAME qrt_ftqc_bit_flip_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/error_correcting_code.cpp)
add_test(NAME qrt_ftqc_five_qubit_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/five_qubit_qec_code.cpp)
add_test(NAME qrt_ftqc_steane_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/steane_qec_code.cpp)
\ No newline at end of file
add_test(NAME qrt_ftqc_steane_qec_std_lib COMMAND ${CMAKE_BINARY_DIR}/qcor -c -qrt ftqc ${CMAKE_CURRENT_SOURCE_DIR}/ftqc_qrt/steane_qec_code.cpp)
add_test(NAME qsim_vqe COMMAND ${CMAKE_BINARY_DIR}/qcor ${CMAKE_CURRENT_SOURCE_DIR}/qsim/VqeWithAnsatzCircuit.cpp)
add_test(NAME qsim_trotter COMMAND ${CMAKE_BINARY_DIR}/qcor ${CMAKE_CURRENT_SOURCE_DIR}/qsim/TrotterTdWorkflow.cpp)
add_test(NAME qsim_iqpe_vqe COMMAND ${CMAKE_BINARY_DIR}/qcor ${CMAKE_CURRENT_SOURCE_DIR}/qsim/IterativeQpeVqe.cpp)
......@@ -24,7 +24,7 @@ int main(int argc, char **argv) {
auto problemModel =
qsim::ModelBuilder::createModel(eigen_state_prep, H, 2, 0);
// Instantiate an IQPE workflow.
// Instantiate an IQPE workflow
auto workflow =
qsim::getWorkflow("iqpe", {{"time-steps", 8}, {"iterations", 8}});
......
#include "qcor_qsim.hpp"
// Using noise-mitigation observable evaluation (Verified QPE)
// Compile and run with (e.g. using the 5-qubit Yorktown device)
/// $ qcor -qpu -qpu aer[noise-model:<noise JSON>] -shots 8192 -opt-pass
/// two-qubit-block-merging VerifiedQuantumPhaseEstimation.cpp
/// $ ./a.out
// For this simple circuit, the Trotter circuit can be significantly simplified
// by the `two-qubit-block-merging` optimizer (combine Trotter steps and
// decompose the total circuit into a more efficient KAK circuit).
// Note: for simplicity, we use the time-dependent Ising model with only 2
// qubits, hence with QPE, we need a total of 3 qubits. These 3 qubits can be
// directly mapped to the triangular topology of the Yorktown device.
// (Ref: Fig 3 of PhysRevB.101.184305)
int main(int argc, char **argv) {
// Define the time-dependent Hamiltonian and observable operator using the
// QCOR API Time-dependent Hamiltonian
qsim::TdObservable H = [](double t) {
// Parameters:
const double Jz = 2 * M_PI * 2.86265 * 1e-3;
const double epsilon = Jz;
const double omega = 4.8 * 2 * M_PI * 1e-3;
return -Jz * Z(0) * Z(1) - epsilon * std::cos(omega * t) * (X(0) + X(1));
};
// Observable = average magnetization
auto observable = (1.0 / 2.0) * (Z(0) + Z(1));
// Example: build model and TD workflow for Fig. 2 of
// https://journals.aps.org/prb/pdf/10.1103/PhysRevB.101.184305
auto problemModel = qsim::ModelBuilder::createModel(observable, H);
// Trotter step = 3fs, number of steps = 100 -> end time = 300fs
// Request the Verified QPE observable evaluator:
auto vqpeEvaluator =
qsim::getObjEvaluator(observable, "qpe", {{"verified", true}});
auto workflow =
qsim::getWorkflow("td-evolution", {{"method", "trotter"},
{"dt", 3.0},
{"steps", 100},
{"evaluator", vqpeEvaluator}});
// Result should contain the observable expectation value along Trotter steps.
auto result = workflow->execute(problemModel);
// Get the observable values (average magnetization)
const auto obsVals = result.get<std::vector<double>>("exp-vals");
// Print out for debugging:
for (const auto &val : obsVals) {
std::cout << "<Magnetization> = " << val << "\n";
}
return 0;
}
......@@ -25,7 +25,8 @@ int main(int argc, char **argv) {
// Instantiate a VQE workflow with the nlopt optimizer
auto workflow = qsim::getWorkflow("vqe", {{"optimizer", optimizer}});
// Result should contain the observable expectation value along Trotter steps.
// Result should contain the ground-state energy along with the optimal
// parameters.
auto result = workflow->execute(problemModel);
const auto energy = result.get<double>("energy");
......
......@@ -26,11 +26,17 @@ protected:
public:
KernelFunctor() = default;
KernelFunctor(qreg qReg) : q(qReg){};
// Direct construction via a Composite Instruction
KernelFunctor(std::shared_ptr<CompositeInstruction> composite) {
kernel = composite;
q = qalloc(composite->nPhysicalBits());
nbParams = composite->nVariables();
}
qreg &getQreg() { return q; }
size_t nParams() const { return nbParams; }
virtual std::shared_ptr<CompositeInstruction>
evaluate_kernel(const std::vector<double> &in_params) {
return nullptr;
return kernel ? kernel->operator()(in_params) : nullptr;
}
};
......@@ -101,4 +107,9 @@ std::shared_ptr<KernelFunctor> createKernelFunctor(
return std::make_shared<KernelFunctorImpl<Args...>>(
kernel_ptr, args_translator, helper, q, nParams);
}
inline std::shared_ptr<KernelFunctor>
createKernelFunctor(std::shared_ptr<CompositeInstruction> composite) {
return std::make_shared<KernelFunctor>(composite);
}
} // namespace qcor
\ No newline at end of file
......@@ -10,6 +10,13 @@ bool CostFunctionEvaluator::initialize(Observable *observable,
return target_operator != nullptr;
}
void executePassManager(
std::vector<std::shared_ptr<CompositeInstruction>> evalKernels) {
for (auto &subKernel : evalKernels) {
execute_pass_manager(subKernel);
}
}
QuantumSimulationModel
ModelBuilder::createModel(Observable *obs, TdObservable td_ham,
const HeterogeneousMap &params) {
......
......@@ -140,6 +140,22 @@ public:
PauliOperator &obs, size_t nbQubits, size_t nbParams) {
return createModel(quantum_kernel_functor, &obs, nbQubits, nbParams);
}
// Passing the state-preparation ansatz as a CompositeInstruction
static inline QuantumSimulationModel
createModel(std::shared_ptr<CompositeInstruction> composite,
Observable *obs) {
QuantumSimulationModel model;
model.observable = obs;
model.user_defined_ansatz = createKernelFunctor(composite);
return model;
}
static inline QuantumSimulationModel
createModel(std::shared_ptr<CompositeInstruction> composite,
PauliOperator &obs) {
return createModel(composite, &obs);
}
};
// Quantum Simulation Workflow (Protocol)
......@@ -171,5 +187,9 @@ getObjEvaluator(PauliOperator &obs, const std::string &name = "default",
const HeterogeneousMap &init_params = {}) {
return getObjEvaluator(&obs, name, init_params);
}
// Helper to apply optimization/placement before evaluation:
void executePassManager(
std::vector<std::shared_ptr<CompositeInstruction>> evalKernels);
} // namespace qsim
} // namespace qcor
\ No newline at end of file
......@@ -40,6 +40,5 @@ install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins)
install(FILES ${HEADERS} DESTINATION include/qcor)
if (QCOR_BUILD_TESTS)
add_subdirectory(tests)
add_subdirectory(modules/tests)
endif()
\ No newline at end of file
link_directories(${XACC_ROOT}/lib)
add_executable(TimeSeriesQpeTester TimeSeriesQpeTester.cpp)
add_test(NAME qcor_TimeSeriesQpeTester COMMAND TimeSeriesQpeTester)
target_include_directories(TimeSeriesQpeTester PRIVATE ../../ ../../../base ${XACC_ROOT}/include/gtest ${XACC_ROOT}/include/eigen)
link_directories(${XACC_ROOT}/lib)
target_link_libraries(TimeSeriesQpeTester ${XACC_ROOT}/lib/libgtest.so ${XACC_ROOT}/lib/libgtest_main.so xacc::xacc xacc::quantum_gate qcor-qsim)
target_link_libraries(TimeSeriesQpeTester ${XACC_TEST_LIBRARIES} xacc::xacc xacc::quantum_gate qcor-qsim)
add_executable(TimeSeriesQpeNoiseTester TimeSeriesQpeNoiseTester.cpp)
add_test(NAME qcor_TimeSeriesQpeNoiseTester COMMAND TimeSeriesQpeNoiseTester)
target_include_directories(TimeSeriesQpeNoiseTester PRIVATE ../../ ../../../base ${XACC_ROOT}/include/gtest ${XACC_ROOT}/include/eigen)
link_directories(${XACC_ROOT}/lib)
target_compile_definitions(TimeSeriesQpeNoiseTester PRIVATE RESOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/resources")
target_link_libraries(TimeSeriesQpeNoiseTester ${XACC_ROOT}/lib/libgtest.so ${XACC_ROOT}/lib/libgtest_main.so xacc::xacc xacc::quantum_gate qcor-qsim)
\ No newline at end of file
target_link_libraries(TimeSeriesQpeNoiseTester ${XACC_TEST_LIBRARIES} xacc::xacc xacc::quantum_gate qcor-qsim)
add_executable(VqeWorkflowTester VqeWorkflowTester.cpp)
add_test(NAME qcor_VqeWorkflowTester COMMAND VqeWorkflowTester)
target_include_directories(VqeWorkflowTester PRIVATE ../../ ../../../base ${XACC_ROOT}/include/gtest)
target_link_libraries(VqeWorkflowTester ${XACC_TEST_LIBRARIES} xacc::xacc xacc::quantum_gate qcor-qsim)
\ No newline at end of file
#include "qcor.hpp"
#include "qcor_qsim.hpp"
#include "xacc.hpp"
#include <gtest/gtest.h>
TEST(VqeWorkflowTest, checkInputComposite) {
using namespace qcor;
auto observable = 5.907 - 2.1433 * X(0) * X(1) - 2.1433 * Y(0) * Y(1) +
.21829 * Z(0) - 6.125 * Z(1);
xacc::internal_compiler::qpu = xacc::getAccelerator("qpp");
auto xasm = xacc::getCompiler("xasm");
auto tmp = xasm->compile(R"#(__qpu__ void ansatz(qbit q, double theta) {
X(q[0]);
exp_i_theta(q, theta, {{"pauli", "X0 Y1 - Y0 X1"}});
}
)#");
auto kernel = tmp->getComposites()[0];
auto H = 5.907 - 2.1433 * X(0) * X(1) - 2.143 * Y(0) * Y(1) + 0.21829 * Z(0) -
6.125 * Z(1);
auto problemModel = qsim::ModelBuilder::createModel(kernel, H);
auto optimizer = createOptimizer("nlopt");
// Instantiate a VQE workflow with the nlopt optimizer
auto workflow = qsim::getWorkflow("vqe", {{"optimizer", optimizer}});
auto result = workflow->execute(problemModel);
const auto energy = result.get<double>("energy");
std::cout << "Min energy: " << energy << "\n";
EXPECT_NEAR(energy, -1.748, 0.1);
}
int main(int argc, char **argv) {
xacc::Initialize();
::testing::InitGoogleTest(&argc, argv);
auto ret = RUN_ALL_TESTS();
xacc::Finalize();
return ret;
}
\ No newline at end of file
......@@ -158,10 +158,10 @@ double PhaseEstimationObjFuncEval::evaluate(
obsTermTracking.emplace_back(std::make_pair(termCoeff, termData));
}
auto qpu = xacc::internal_compiler::get_qpu();
auto temp_buffer = xacc::qalloc(nbQubits + 1);
// Execute all sub-kernels
qpu->execute(temp_buffer, fsToExec);
executePassManager(fsToExec);
xacc::internal_compiler::execute(temp_buffer.get(), fsToExec);
// Assemble execution data into a fast look-up map
ExecutionData exeResult;
......@@ -172,6 +172,7 @@ double PhaseEstimationObjFuncEval::evaluate(
const auto mitigateMeasurementResult =
[&](const std::map<std::string, int> &in_rawResult) {
std::map<std::string, int> result{{"0", 0}, {"1", 0}};
auto qpu = xacc::internal_compiler::get_qpu();
const size_t bitIdx =
(qpu->getBitOrder() == Accelerator::BitOrder::MSB) ? 0 : nbQubits;
const std::string CORRECT_VERIFIED_BITSTRING(nbQubits, '0');
......
......@@ -2,6 +2,26 @@
#include "xacc.hpp"
#include "xacc_service.hpp"
namespace {
using namespace qcor;
std::shared_ptr<qsim::CostFunctionEvaluator>
getEvaluator(Observable *observable, const HeterogeneousMap &params) {
// If an evaluator was provided explicitly:
if (params.pointerLikeExists<qsim::CostFunctionEvaluator>("evaluator")) {
return xacc::as_shared_ptr(
params.getPointerLike<qsim::CostFunctionEvaluator>("evaluator"));
}
// Cost Evaluator was provided by name:
if (params.stringExists("evaluator")) {
return qsim::getObjEvaluator(observable, params.getString("evaluator"));
}
// No specific evaluator/evaluation method was requested,
// use the default one (partial tomography based).
return qsim::getObjEvaluator(observable);
}
} // namespace
namespace qcor {
namespace qsim {
Ansatz TrotterEvolution::create_ansatz(Observable *obs,
......@@ -37,13 +57,14 @@ bool TimeDependentWorkflow::initialize(const HeterogeneousMap &params) {
}
t_final = nbSteps * dt;
config_params = params;
return true;
}
QuantumSimulationResult
TimeDependentWorkflow::execute(const QuantumSimulationModel &model) {
QuantumSimulationResult result;
evaluator = getObjEvaluator(model.observable);
evaluator = getEvaluator(model.observable, config_params);
auto ham_func = model.hamiltonian;
// A TD workflow: stepping through Trotter steps,
// compute expectations at each step.
......@@ -100,12 +121,7 @@ VqeWorkflow::execute(const QuantumSimulationModel &model) {
// If the model includes a concrete variational ansatz:
if (model.user_defined_ansatz) {
auto nParams = model.user_defined_ansatz->nParams();
if (config_params.pointerLikeExists<CostFunctionEvaluator>("evaluator")) {
evaluator = xacc::as_shared_ptr(
config_params.getPointerLike<CostFunctionEvaluator>("evaluator"));
} else {
evaluator = getObjEvaluator(model.observable);
}
evaluator = getEvaluator(model.observable, config_params);
OptFunction f(
[&](const std::vector<double> &x, std::vector<double> &dx) {
......@@ -269,11 +285,9 @@ IterativeQpeWorkflow::execute(const QuantumSimulationModel &model) {
auto iterQpe = constructQpeCircuit(stretchedObs, k, -2 * M_PI * omega_coef);
kernel->addInstruction(iterQpe);
// Executes the iterative QPE algorithm:
auto qpu = xacc::internal_compiler::get_qpu();
auto temp_buffer = xacc::qalloc(stretchedObs->nBits() + 1);
// std::cout << "Kernel: \n" << kernel->toString() << "\n";
qpu->execute(temp_buffer, kernel);
xacc::internal_compiler::execute(temp_buffer.get(), kernel);
// temp_buffer->print();
// Estimate the phase value's bit at this iteration,
......@@ -322,14 +336,13 @@ getWorkflow(const std::string &name, const HeterogeneousMap &init_params) {
double
DefaultObjFuncEval::evaluate(std::shared_ptr<CompositeInstruction> state_prep) {
// Reuse existing VQE util to evaluate the expectation value:
auto vqe = xacc::getAlgorithm("vqe");
auto qpu = xacc::internal_compiler::get_qpu();
vqe->initialize({{"ansatz", state_prep},
{"accelerator", qpu},
{"observable", target_operator}});
auto tmp_child = qalloc(state_prep->nPhysicalBits());
auto energy = vqe->execute(xacc::as_shared_ptr(tmp_child.results()), {})[0];
auto subKernels = qcor::__internal__::observe(
xacc::as_shared_ptr(target_operator), state_prep);
// Run the pass manager (optimization + placement)
executePassManager(subKernels);
auto tmp_buffer = qalloc(state_prep->nPhysicalBits());
xacc::internal_compiler::execute(tmp_buffer.results(), subKernels);
const double energy = tmp_buffer.weighted_sum(target_operator);
return energy;
}
} // namespace qsim
......
......@@ -25,22 +25,6 @@ public:
virtual const std::string description() const override { return ""; }
};
// other methods.
// Estimate the cost function based on bitstring distribution,
// e.g. actual quantum hardware.
// Note: we can sub-class CostFunctionEvaluator to add post-processing or
// analysis of the result.
class BitCountExpectationEstimator : public CostFunctionEvaluator {
public:
// Evaluate the cost
virtual double
evaluate(std::shared_ptr<CompositeInstruction> state_prep) override;
private:
size_t nb_samples;
};
// VQE-type workflow which involves an optimization loop, i.e. an Optimizer.
class VqeWorkflow : public QuantumSimulationWorkflow {
public:
......@@ -67,6 +51,7 @@ public:
virtual const std::string description() const override { return ""; }
private:
HeterogeneousMap config_params;
double t_0;
double t_final;
double dt;
......
add_test(NAME qsim_vqe COMMAND ${CMAKE_BINARY_DIR}/qcor ${CMAKE_CURRENT_SOURCE_DIR}/VqeWithAnsatzCircuit.cpp)
add_test(NAME qsim_trotter COMMAND ${CMAKE_BINARY_DIR}/qcor ${CMAKE_CURRENT_SOURCE_DIR}/TrotterTdWorkflow.cpp)
add_test(NAME qsim_iqpe_simple COMMAND ${CMAKE_BINARY_DIR}/qcor ${CMAKE_CURRENT_SOURCE_DIR}/IterativeQpeSimple.cpp)
add_test(NAME qsim_iqpe_vqe COMMAND ${CMAKE_BINARY_DIR}/qcor ${CMAKE_CURRENT_SOURCE_DIR}/IterativeQpeVqe.cpp)
#include "qcor_qsim.hpp"
// Solving the ground-state energy of a Hamiltonian operator by the iterative
// QPE procedure.
// 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) {
using qcor::openqasm;
u3(0.95531662,0,0) q[0];
u1(pi/4) q[0];
}
int main(int argc, char **argv) {
// Create Hamiltonian:
auto H = 1.0 + X(0) + Y(0) + Z(0);
auto problemModel =
qsim::ModelBuilder::createModel(eigen_state_prep, H, 1, 0);
// Instantiate an IQPE workflow.
auto workflow =
qsim::getWorkflow("iqpe", {{"time-steps", 4}, {"iterations", 4}});
auto result = workflow->execute(problemModel);
const double phaseValue = result.get<double>("phase");
const double energy = result.get<double>("energy");
std::cout << "Final phase = " << phaseValue << "\n";
std::cout << "Energy = " << energy << "\n";
return 0;
}
\ No newline at end of file
#include "qcor_qsim.hpp"
// High-level usage of Model Builder for typical VQE problem.
// Compile and run with:
// (need shots to do verification)
/// $ qcor -qpu qpp -shots 8192 VqeWithVerifiedQpeMitigation.cpp
/// $ ./a.out
// Define a fixed ansatz as a QCOR kernel
__qpu__ void ansatz(qreg q, double theta) {
X(q[0]);
auto exponent_op = X(0) * Y(1) - Y(0) * X(1);
exp_i_theta(q, theta, exponent_op);
}
int main(int argc, char **argv) {
// Create the Deuteron 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);
const auto num_qubits = 2;
const auto num_params = 1;
// QPE with verification
auto costEvaluator = qsim::getObjEvaluator(H, "qpe", {{"verified", true}});
// QPE no verification
// auto costEvaluator = qsim::getObjEvaluator(H, "qpe");
// Default (tomography-based)
// auto costEvaluator = qsim::getObjEvaluator(H);
auto problemModel =
qsim::ModelBuilder::createModel(ansatz, H, num_qubits, num_params);
// Initial parameters: we evaluate the error at single data points.
const std::vector<double> init_params{0.297113};
auto optimizer = createOptimizer(
"nlopt", {{"nlopt-maxeval", 1}, {"initial-parameters", init_params}});
// Instantiate a VQE workflow with the nlopt optimizer
auto workflow = qsim::getWorkflow(
"vqe", {{"optimizer", optimizer}, {"evaluator", costEvaluator}});
// Result should contain the observable expectation value along Trotter steps.
auto result = workflow->execute(problemModel);
const auto energy = result.get<double>("energy");
std::cout << "Ground-state energy = " << energy << "\n";
return 0;
}
\ No newline at end of file
......@@ -57,6 +57,7 @@ observe(std::shared_ptr<xacc::Observable> obs,
std::shared_ptr<CompositeInstruction> program) {
return obs->observe(program);
}
} // namespace __internal__
double observe(std::shared_ptr<CompositeInstruction> program,
std::shared_ptr<xacc::Observable> obs,
......@@ -86,5 +87,4 @@ double observe(std::shared_ptr<CompositeInstruction> program, Observable &obs,
return q.weighted_sum(&obs);
}();
}
} // namespace __internal__
} // namespace qcor
\ No newline at end of file
......@@ -89,11 +89,12 @@ double observe(std::shared_ptr<CompositeInstruction> program, Observable &obs,
double observe(std::shared_ptr<CompositeInstruction> program,
std::shared_ptr<Observable> obs,
xacc::internal_compiler::qreg &q);
namespace __internal__ {
// Observe the kernel and return the measured kernels
std::vector<std::shared_ptr<CompositeInstruction>>
observe(std::shared_ptr<Observable> obs,
std::shared_ptr<CompositeInstruction> program);
} // namespace __internal__
// Create an observable from a string representation
std::shared_ptr<Observable> createObservable(const std::string &repr);
......
......@@ -18,10 +18,14 @@ std::string __placement_name = "";
std::vector<int> __qubit_map = {};
std::string __qrt_env = "nisq";
void execute_pass_manager() {
void execute_pass_manager(
std::shared_ptr<CompositeInstruction> optional_composite) {
qcor::internal::PassManager passManager(__opt_level, __qubit_map,
__placement_name);
auto optData = passManager.optimize(::quantum::qrt_impl->get_current_program());
auto kernelToExecute = optional_composite
? optional_composite
: ::quantum::qrt_impl->get_current_program();
auto optData = passManager.optimize(kernelToExecute);
std::vector<std::string> user_passes;
if (!__user_opt_passes.empty()) {
......@@ -37,7 +41,7 @@ void execute_pass_manager() {
// Runs user-specified passes
for (const auto &user_pass : user_passes) {
optData.emplace_back(
qcor::internal::PassManager::runPass(user_pass, ::quantum::qrt_impl->get_current_program()));
qcor::internal::PassManager::runPass(user_pass, kernelToExecute));
}
if (__print_opt_stats) {
......@@ -47,7 +51,7 @@ void execute_pass_manager() {
}
}
passManager.applyPlacement(::quantum::qrt_impl->get_current_program());
passManager.applyPlacement(kernelToExecute);
}
std::vector<int> parse_qubit_map(const char *qubit_map_str) {
......
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