Skip to content

Commit 755db90

Browse files
authored
Add custom target and pass managers (#141)
* add customization of Target, add StagedPassManager and preset pass managers * add target test * fix test * fix test * fix parameter for qk_transpile_stage_optimization * fix test * fix test, fix QuantumCircuit::operator== * fix for Windows
1 parent 702c7f6 commit 755db90

22 files changed

Lines changed: 855 additions & 103 deletions

samples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ endfunction()
101101

102102
add_application(circuit_test circuit_test.cpp)
103103
add_application(observable_test observable_test.cpp)
104+
add_application(target_test target_test.cpp)
104105

105106
if(QRMI_ROOT OR QISKIT_IBM_RUNTIME_C_ROOT OR SQC_ROOT)
106107
add_application(sampler_test sampler_test.cpp)

samples/target_test.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
# This code is part of Qiskit.
3+
#
4+
# (C) Copyright IBM 2024.
5+
#
6+
# This code is licensed under the Apache License, Version 2.0. You may
7+
# obtain a copy of this license in the LICENSE.txt file in the root directory
8+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
9+
#
10+
# Any modifications or derivative works of this code must retain this
11+
# copyright notice, and modified files need to carry a notice indicating
12+
# that they have been altered from the originals.
13+
*/
14+
15+
// Test program for local target
16+
17+
#define _USE_MATH_DEFINES
18+
#include <iostream>
19+
#include <cstdint>
20+
#include <cstdlib>
21+
#include <cmath>
22+
23+
#include "circuit/quantumcircuit.hpp"
24+
#include "transpiler/target.hpp"
25+
#include "transpiler/passmanager.hpp"
26+
#include "transpiler/preset_passmanagers/generate_preset_pass_manager.hpp"
27+
28+
using namespace Qiskit::circuit;
29+
using namespace Qiskit::transpiler;
30+
31+
int main()
32+
{
33+
QuantumRegister qr(4);
34+
ClassicalRegister cr(4);
35+
QuantumCircuit circ(qr, cr);
36+
37+
circ.h(0);
38+
for (int i=1;i<4;i++) {
39+
circ.cx(0, i);
40+
}
41+
for (int i=0;i<4;i++) {
42+
circ.measure(i,i);
43+
}
44+
45+
std::cout << "input circuit" << std::endl;
46+
circ.print();
47+
48+
49+
auto target = Target({"h", "cx"}, {{0, 1}, {1, 0}, {1, 3}, {3, 1}, {0, 2}, {2, 0}, {2, 3}, {3, 2}});
50+
// auto target = Target({"cz", "id", "rx", "rz", "rzz", "sx", "x"}, {{0, 1}, {1, 0}, {1, 3}, {3, 1}, {0, 2}, {2, 0}, {2, 3}, {3, 2}});
51+
auto pass = StagedPassManager({"init", "layout", "routing", "translation", "optimization"}, target);
52+
//auto pass = generate_preset_pass_manager(2, {"h", "cx"}, {{0, 1}, {1, 0}, {1, 3}, {3, 1}, {0, 2}, {2, 0}, {2, 3}, {3, 2}}, 1.0, 1);
53+
auto transpiled = pass.run(circ);
54+
55+
std::cout << "transpiled circuit" << std::endl;
56+
transpiled.print();
57+
58+
return 0;
59+
}
60+

src/circuit/controlflow/control_flow.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class ControlFlowOp
2929
{
3030
protected:
3131
// TO DO : this is temporary, make condition class to handle multiple conditions
32-
Expr expr_;
32+
//Expr expr_;
3333
uint32_t clbit_;
3434
uint32_t value_;
3535
public:
@@ -44,7 +44,7 @@ class ControlFlowOp
4444

4545
/// @brief Create a new instruction.
4646
/// @param (expr) expression
47-
ControlFlowOp(Expr expr) : expr_(expr) {}
47+
//ControlFlowOp(Expr expr) : expr_(expr) {}
4848

4949
virtual void add_control_flow_op(QuantumCircuit& circ) = 0;
5050
};

src/circuit/quantumcircuit_def.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,11 @@
2323

2424
#include "utils/types.hpp"
2525
#include "circuit/parameter.hpp"
26-
#include "circuit/classical/expr.hpp"
26+
//#include "circuit/classical/expr.hpp"
2727
#include "circuit/classicalregister.hpp"
2828
#include "circuit/quantumregister.hpp"
2929
#include "circuit/library/standard_gates/standard_gates.hpp"
3030
#include "circuit/circuitinstruction.hpp"
31-
#include "transpiler/target.hpp"
3231

3332
#include <complex>
3433
#include "qiskit.h"
@@ -156,7 +155,7 @@ class QuantumCircuit
156155
/// @param circ smart pointer to RUst circuit
157156
/// @param map layout mapping
158157
void set_qiskit_circuit(std::shared_ptr<rust_circuit> circ, const std::vector<uint32_t> &map);
159-
158+
160159
/// @brief get qubit mapping
161160
/// @return qubit mapping
162161
const reg_t &get_qubit_map(void)
@@ -690,6 +689,15 @@ class QuantumCircuit
690689
/// @brief print circuit (this is for debug)
691690
void print(void) const;
692691

692+
693+
/// @brief compare two circuits
694+
/// @param other a circuit to be compared with this circuit
695+
/// @return true if two circuits are the same
696+
bool operator==(const QuantumCircuit& other) const;
697+
bool operator!=(const QuantumCircuit& other) const
698+
{
699+
return !(*this == other);
700+
}
693701
protected:
694702
void add_pending_control_flow_op(void);
695703

src/circuit/quantumcircuit_impl.hpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020

2121
#include <memory>
2222
#include <functional>
23+
#include <iostream>
24+
#include <vector>
25+
#include <algorithm>
2326
#include <iomanip>
2427
#include <cstring>
28+
#include <cassert>
2529

2630
#include "controlflow/__init__.hpp"
2731

@@ -1583,6 +1587,65 @@ std::string QuantumCircuit::to_qasm3(void)
15831587
return qasm3.str();
15841588
}
15851589

1590+
1591+
bool QuantumCircuit::operator==(const QuantumCircuit& other) const
1592+
{
1593+
if (global_phase_ != other.global_phase_) {
1594+
return false;
1595+
}
1596+
1597+
// compare instructions
1598+
uint_t nops;
1599+
uint_t nops_other;
1600+
nops = qk_circuit_num_instructions(rust_circuit_.get());
1601+
nops_other = qk_circuit_num_instructions(other.rust_circuit_.get());
1602+
if (nops != nops_other) {
1603+
return false;
1604+
}
1605+
1606+
for (uint_t i = 0; i < nops; i++) {
1607+
QkCircuitInstruction *op = new QkCircuitInstruction;
1608+
QkCircuitInstruction *op_other = new QkCircuitInstruction;
1609+
qk_circuit_get_instruction(rust_circuit_.get(), i, op);
1610+
qk_circuit_get_instruction(other.rust_circuit_.get(), i, op_other);
1611+
1612+
if (std::string(op->name) != std::string(op_other->name)) {
1613+
qk_circuit_instruction_clear(op);
1614+
qk_circuit_instruction_clear(op_other);
1615+
return false;
1616+
}
1617+
if (op->num_qubits != op_other->num_qubits || op->num_clbits != op_other->num_clbits || op->num_params != op_other->num_params) {
1618+
qk_circuit_instruction_clear(op);
1619+
qk_circuit_instruction_clear(op_other);
1620+
return false;
1621+
}
1622+
for (int j = 0; j < op->num_qubits; j++) {
1623+
if (op->qubits[j] != op_other->qubits[j]) {
1624+
qk_circuit_instruction_clear(op);
1625+
qk_circuit_instruction_clear(op_other);
1626+
return false;
1627+
}
1628+
}
1629+
for (int j = 0; j < op->num_params; j++) {
1630+
if (op->params[j] != op_other->params[j]) {
1631+
qk_circuit_instruction_clear(op);
1632+
qk_circuit_instruction_clear(op_other);
1633+
return false;
1634+
}
1635+
}
1636+
for (int j = 0; j < op->num_clbits; j++) {
1637+
if (op->clbits[j] != op_other->clbits[j]) {
1638+
qk_circuit_instruction_clear(op);
1639+
qk_circuit_instruction_clear(op_other);
1640+
return false;
1641+
}
1642+
}
1643+
}
1644+
return true;
1645+
}
1646+
1647+
1648+
15861649
} // namespace circuit
15871650
} // namespace Qiskit
15881651

src/compiler/transpiler.hpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ namespace compiler {
3434
circuit::QuantumCircuit transpile(circuit::QuantumCircuit &circ, providers::BackendV2 &backend, int optimization_level = 2, double approximation_degree = 1.0, int seed_transpiler = -1)
3535
{
3636
auto target = backend.target();
37-
if (target == nullptr)
38-
{
39-
return circ;
37+
auto capi_target = target.rust_target();
38+
if (capi_target == nullptr) {
39+
std::cerr << "transpile error : Target object for the backend is not valid." << std::endl;
40+
return circ.copy();
4041
}
4142

4243
QkTranspileOptions options = qk_transpiler_default_options();
@@ -47,12 +48,10 @@ circuit::QuantumCircuit transpile(circuit::QuantumCircuit &circ, providers::Back
4748
QkTranspileResult result;
4849
char *error;
4950

50-
QkExitCode ret = qk_transpile(circ.get_rust_circuit().get(), target->rust_target(), &options, &result, &error);
51-
if (ret != QkExitCode_Success)
52-
{
51+
QkExitCode ret = qk_transpile(circ.get_rust_circuit().get(), capi_target, &options, &result, &error);
52+
if (ret != QkExitCode_Success) {
5353
std::cerr << "transpile error (" << ret << ") : " << error << std::endl;
54-
target.reset();
55-
return circ;
54+
return circ.copy();
5655
}
5756

5857
// save qubit map after transpile
@@ -63,8 +62,6 @@ circuit::QuantumCircuit transpile(circuit::QuantumCircuit &circ, providers::Back
6362
transpiled.set_qiskit_circuit(std::shared_ptr<rust_circuit>(result.circuit, qk_circuit_free), layout_map);
6463

6564
qk_transpile_layout_free(result.layout);
66-
target.reset();
67-
6865
return transpiled;
6966
}
7067

src/primitives/backend_sampler_job.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define __qiskitcpp_primitives_qrmi_qiskit_ibm_runtime_job_def_hpp__
1919

2020
#ifdef _MSC_VER
21+
#define NOMINMAX
2122
#include <windows.h>
2223
#else
2324
#include <thread>

src/providers/backend.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class BackendV2 {
6060

6161
/// @brief Return a target properties for this backend
6262
/// @return a target class
63-
virtual std::shared_ptr<transpiler::Target> target(void) = 0;
63+
virtual const transpiler::Target& target(void) = 0;
6464

6565
/// @brief Run and collect samples from each pub.
6666
/// @param pubs An iterable of pub-like objects.

src/providers/qkrt_backend.hpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class QkrtBackend : public BackendV2 {
4444
std::string primitive_name_ = "sampler";
4545
qkrt_Backend* backend_ = nullptr;
4646
std::shared_ptr<qkrt_Service> service_;
47-
std::shared_ptr<transpiler::Target> target_ = nullptr;
47+
transpiler::Target target_;
4848
public:
4949
/// @brief Create a new QkrtBackend
5050
QkrtBackend() {}
@@ -72,24 +72,22 @@ class QkrtBackend : public BackendV2 {
7272
{
7373
if (service_)
7474
service_.reset();
75-
if (target_)
76-
target_.reset();
7775
}
7876

7977
/// @brief Return a target properties for this backend
8078
/// @return a target class
81-
std::shared_ptr<transpiler::Target> target(void) override
79+
const transpiler::Target& target(void) override
8280
{
83-
if (target_) {
81+
if (target_.is_set()) {
8482
return target_;
8583
}
8684

8785
QkTarget *target = qkrt_get_backend_target(service_.get(), backend_);
8886
if (target == nullptr) {
8987
std::cerr << "ERROR: failed to get target for the backend " << name_ << std::endl;
90-
return nullptr;
88+
return target_;
9189
}
92-
target_ = std::make_shared<transpiler::Target>(target);
90+
target_ = transpiler::Target(target);
9391
return target_;
9492
}
9593

src/providers/qrmi_backend.hpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class QRMIBackend : public BackendV2 {
3636
std::string primitive_name_ = "sampler";
3737
std::string acc_token_;
3838
std::shared_ptr<QrmiQuantumResource> qrmi_ = nullptr;
39-
std::shared_ptr<transpiler::Target> target_ = nullptr;
39+
transpiler::Target target_;
4040
public:
4141
/// @brief Create a new QRMIBackend
4242
QRMIBackend() {}
@@ -68,22 +68,21 @@ class QRMIBackend : public BackendV2 {
6868

6969
/// @brief Return a target properties for this backend
7070
/// @return a target class
71-
std::shared_ptr<transpiler::Target> target(void) override
71+
const transpiler::Target& target(void) override
7272
{
73-
if (target_) {
73+
if (target_.is_set()) {
7474
return target_;
7575
}
76-
transpiler::Target target;
7776

7877
char *target_str = NULL;
7978
QrmiReturnCode rc = qrmi_resource_target(qrmi_.get(), &target_str);
8079
if (rc != QRMI_RETURN_CODE_SUCCESS) {
81-
return nullptr;
80+
return target_;
8281
}
8382
nlohmann::ordered_json json_target = nlohmann::ordered_json::parse(target_str);
8483
qrmi_string_free((char *)target_str);
85-
target_ = std::make_shared<transpiler::Target>();
86-
target_->from_json(json_target);
84+
target_ = transpiler::Target();
85+
target_.from_json(json_target);
8786
return target_;
8887
}
8988

0 commit comments

Comments
 (0)