Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ Refactor QASM import functionality and remove deprecated formats #822

Merged
merged 6 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions docs/mqt_core_ir.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,16 +298,37 @@ qc.append(classic_controlled)
print(qc)
```

## Interfacing with other SDKs
## Interfacing with other SDKs and Formats

Since a {py:class}`~mqt.core.ir.QuantumComputation` can be imported from and exported to an OpenQASM 3.0 (or OpenQASM 2.0) string, any library that can work with OpenQASM is easy to use in conjunction with the {py:class}`~mqt.core.ir.QuantumComputation` class.
### OpenQASM

In addition, `mqt-core` can import [Qiskit](https://qiskit.org/) {py:class}`~qiskit.circuit.QuantumCircuit` objects directly.
OpenQASM is a widely used format for representing quantum circuits.
Its latest version, [OpenQASM 3](https://openqasm.com/index.html), is a powerful language that can express a wide range of quantum circuits.
MQT Core supports the full functionality of OpenQASM 2.0 (including classically controlled operations) and a growing subset of OpenQASM 3.

```{code-cell} ipython3
from qiskit import QuantumCircuit
from mqt.core.ir import QuantumComputation

from mqt.core.plugins.qiskit import qiskit_to_mqt
qasm_str = """
OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
h q[0];
cx q[0], q[1];
cx q[0], q[2];
"""

qc = QuantumComputation.from_qasm_str(qasm_str)

print(qc)
```

### Qiskit

In addition to OpenQASM, `mqt-core` can natively import [Qiskit](https://qiskit.org/) {py:class}`~qiskit.circuit.QuantumCircuit` objects.

```{code-cell} ipython3
from qiskit import QuantumCircuit

# GHZ circuit in qiskit
qiskit_qc = QuantumCircuit(3)
Expand All @@ -319,6 +340,8 @@ qiskit_qc.draw(output="mpl", style="iqp")
```

```{code-cell} ipython3
from mqt.core.plugins.qiskit import qiskit_to_mqt

mqt_qc = qiskit_to_mqt(qiskit_qc)
print(mqt_qc)
```
2 changes: 1 addition & 1 deletion include/mqt-core/Definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ static constexpr fp E = static_cast<fp>(
2.718281828459045235360287471352662497757247093699959574967L);

// supported file formats
enum class Format : uint8_t { Real, OpenQASM2, OpenQASM3, TFC, QC, Tensor };
enum class Format : uint8_t { OpenQASM2, OpenQASM3 };

/**
* @brief 64bit mixing hash (from MurmurHash3)
Expand Down
44 changes: 8 additions & 36 deletions include/mqt-core/ir/QuantumComputation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <map>
#include <memory>
#include <optional>
#include <random>
Expand Down Expand Up @@ -68,10 +67,8 @@ class QuantumComputation {
std::unordered_set<sym::Variable> occurringVariables;

public:
QuantumComputation() = default;
explicit QuantumComputation(std::size_t nq, std::size_t nc = 0U,
explicit QuantumComputation(std::size_t nq = 0, std::size_t nc = 0U,
std::size_t s = 0);
explicit QuantumComputation(const std::string& filename, std::size_t s = 0U);
QuantumComputation(QuantumComputation&& qc) noexcept = default;
QuantumComputation& operator=(QuantumComputation&& qc) noexcept = default;
QuantumComputation(const QuantumComputation& qc);
Expand All @@ -82,13 +79,6 @@ class QuantumComputation {
Permutation initialLayout{};
Permutation outputPermutation{};

/**
* @brief Construct a QuantumComputation from an OpenQASM string
* @param qasm The OpenQASM 2.0 or 3.0 string
* @return The constructed QuantumComputation
*/
[[nodiscard]] static QuantumComputation fromQASM(const std::string& qasm);

/**
* @brief Construct a QuantumComputation from CompoundOperation object
* @details The function creates a copy of each operation in the compound
Expand All @@ -114,9 +104,11 @@ class QuantumComputation {
[[nodiscard]] const std::vector<bool>& getAncillary() const noexcept {
return ancillary;
}
[[nodiscard]] std::vector<bool>& getAncillary() noexcept { return ancillary; }
[[nodiscard]] const std::vector<bool>& getGarbage() const noexcept {
return garbage;
}
[[nodiscard]] std::vector<bool>& getGarbage() noexcept { return garbage; }
[[nodiscard]] std::size_t getNcbits() const noexcept { return nclassics; }
[[nodiscard]] std::string getName() const noexcept { return name; }
[[nodiscard]] const auto& getQuantumRegisters() const noexcept {
Expand Down Expand Up @@ -372,9 +364,6 @@ class QuantumComputation {
/// qubits occurring in the output permutation
void stripIdleQubits(bool force = false);

void import(const std::string& filename);
void import(const std::string& filename, Format format);
void import(std::istream& is, Format format);
void initializeIOMapping();
// append measurements to the end of the circuit according to the tracked
// output permutation
Expand Down Expand Up @@ -408,7 +397,8 @@ class QuantumComputation {
void addQubit(Qubit logicalQubitIndex, Qubit physicalQubitIndex,
std::optional<Qubit> outputQubitIndex);

QuantumComputation instantiate(const VariableAssignment& assignment) const;
[[nodiscard]] QuantumComputation
instantiate(const VariableAssignment& assignment) const;
void instantiateInplace(const VariableAssignment& assignment);

void addVariable(const SymbolOrNumber& expr);
Expand Down Expand Up @@ -449,20 +439,15 @@ class QuantumComputation {
static std::ostream& printPermutation(const Permutation& permutation,
std::ostream& os = std::cout);

void dump(const std::string& filename, Format format) const;
void dump(const std::string& filename) const;
void dump(std::ostream& of, Format format) const;
void dumpOpenQASM2(std::ostream& of) const { dumpOpenQASM(of, false); }
void dumpOpenQASM3(std::ostream& of) const { dumpOpenQASM(of, true); }
void dump(const std::string& filename,
Format format = Format::OpenQASM3) const;

/**
* @brief Dumps the circuit in OpenQASM format to the given output stream
* @details One might want to call `ensureContiguousInitialLayout` before
* calling this function to ensure full layout information is available.
* @param of The output stream to write the OpenQASM representation to
* @param openQasm3 Whether to use OpenQASM 3.0 or 2.0
*/
void dumpOpenQASM(std::ostream& of, bool openQasm3) const;
void dumpOpenQASM(std::ostream& of, bool openQasm3 = true) const;

/**
* @brief Returns the OpenQASM representation of the circuit
Expand Down Expand Up @@ -500,19 +485,6 @@ class QuantumComputation {
[[nodiscard]] bool isDynamic() const;

protected:
void importOpenQASM3(std::istream& is);
void importReal(std::istream& is);
int readRealHeader(std::istream& is);
void readRealGateDescriptions(std::istream& is, int line);
void importTFC(std::istream& is);
int readTFCHeader(std::istream& is, std::map<std::string, Qubit>& varMap);
void readTFCGateDescriptions(std::istream& is, int line,
std::map<std::string, Qubit>& varMap);
void importQC(std::istream& is);
int readQCHeader(std::istream& is, std::map<std::string, Qubit>& varMap);
void readQCGateDescriptions(std::istream& is, int line,
std::map<std::string, Qubit>& varMap);

[[nodiscard]] std::size_t getSmallestAncillary() const {
for (std::size_t i = 0; i < ancillary.size(); ++i) {
if (ancillary[i]) {
Expand Down
Loading
Loading