Skip to content

Commit

Permalink
♻️ Refactor QASM import functionality and remove deprecated formats (#…
Browse files Browse the repository at this point in the history
…822)

## Description

This pull request refactors the QASM import functionality by
encapsulating the QASM parser into its own dedicated library,
`MQT::CoreQASM`. This change removes the import functionality from the
`QuantumComputation` class, improving modularity and maintainability.
Additionally, deprecated formats have been removed, streamlining the
codebase.

Notably, this removes support for parsing `.real` files. Corresponding
support is expected to be integrated into the MQT SyReC Synthesizer at
https://github.com/cda-tum/mqt-syrec.

## Checklist:

<!---
This checklist serves as a reminder of a couple of things that ensure
your pull request will be merged swiftly.
-->

- [x] The pull request only contains commits that are related to it.
- [x] I have added appropriate tests and documentation.
- [x] I have made sure that all CI jobs on GitHub pass.
- [x] The pull request introduces no new warnings and follows the
project's style guidelines.
  • Loading branch information
burgholzer authored Feb 4, 2025
2 parents 1d99577 + e7a8e15 commit be654c7
Show file tree
Hide file tree
Showing 58 changed files with 2,455 additions and 5,426 deletions.
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

0 comments on commit be654c7

Please sign in to comment.