Skip to content

Commit

Permalink
♻️ reorganize library structure (#668)
Browse files Browse the repository at this point in the history
## Description

This PR cleans up the library structure within MQT Core.
It separates the library into smaller CMake targets that are each
configured in their own subdirectory.
Most notably, this implies the following changes:
- `MQT::Core` -> `MQT::CoreIR`, `MQT::CoreAlgo`,
`MQT::CoreCircuitOptimizer`
- Disentangle the circuit optimizer from the QuantumComputation class
and only rely on the public API
- Separation of the circuit optimizer tests from the main IR tests
- Each library target now has its own export header
- The GRCS class and parser have been removed as they were not really
used
- Moved the `Grover` specialization for building its functionality to
the `Benchmark` part of the library
- Moved the `reorderOperations` method from the CircuitOptimizer to the
QuantumComputation class to keep the `MQT::CoreIR` target
self-contained.
- Refactors the `mqt.core` Python package. Removes a level of
indirection by directly exposing the bindings module as `mqt.core.ir`

> [!CAUTION]
> This is a breaking change for consuming libraries. Any library relying
on MQT Core will have to adapt accordingly.

## 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 Aug 13, 2024
2 parents 9ddee9e + f490b00 commit b16e6e9
Show file tree
Hide file tree
Showing 183 changed files with 2,384 additions and 8,312 deletions.
3 changes: 0 additions & 3 deletions cmake/mqt-core-config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@ if(TARGET MQT::Core)
endif()

include("${CMAKE_CURRENT_LIST_DIR}/Cache.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/CompilerOptions.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/CompilerWarnings.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/PackageAddTest.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/PreventInSourceBuilds.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/Sanitizers.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/StandardProjectSettings.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/mqt-core-targets.cmake")

Expand Down
14 changes: 7 additions & 7 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@

intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"qiskit": ("https://docs.quantum.ibm.com/api/qiskit/", None),
"mqt": ("https://mqt.readthedocs.io/en/latest/", None),
"ddsim": ("https://mqt.readthedocs.io/projects/ddsim/en/latest/", None),
"qmap": ("https://mqt.readthedocs.io/projects/qmap/en/latest/", None),
"qcec": ("https://mqt.readthedocs.io/projects/qcec/en/latest/", None),
"qecc": ("https://mqt.readthedocs.io/projects/qecc/en/latest/", None),
"syrec": ("https://mqt.readthedocs.io/projects/syrec/en/latest/", None),
"qiskit": ("https://docs.quantum.ibm.com/api/qiskit", None),
"mqt": ("https://mqt.readthedocs.io/en/latest", None),
"ddsim": ("https://mqt.readthedocs.io/projects/ddsim/en/latest", None),
"qmap": ("https://mqt.readthedocs.io/projects/qmap/en/latest", None),
"qcec": ("https://mqt.readthedocs.io/projects/qcec/en/latest", None),
"qecc": ("https://mqt.readthedocs.io/projects/qecc/en/latest", None),
"syrec": ("https://mqt.readthedocs.io/projects/syrec/en/latest", None),
}

myst_enable_extensions = [
Expand Down
14 changes: 7 additions & 7 deletions docs/dd_package_evaluation.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,27 @@ To compare the performance of your newly proposed changes to the existing implem

## Running the comparison

There are two ways to run the comparison. Either you can use the Python module {py:mod}`mqt.core.evaluation` or you can use the CLI.
There are two ways to run the comparison. Either you can use the Python module {py:mod}`mqt.core.dd.evaluation` or you can use the CLI.
Both ways are shown below.
In both cases, you need to have the `evaluation` extra of `mqt-core` (i.e., `mqt.core[evaluation]`) installed.

+++

### Using the Python package

The Python package provides a function {py:func}`~mqt.core.evaluation.compare` that can be used to compare two generate result files.
The Python package provides a function {py:func}`~mqt.core.dd.evaluation.compare` that can be used to compare two generate result files.
The function takes two arguments, the file path of the baseline json and the file path of the json results from your changes.
The function will then print a detailed comparison. An exemplary run is shown below.

```{code-cell} ipython3
from mqt.core.evaluation import compare
from mqt.core.dd.evaluation import compare
baseline_path = "../test/python/results_baseline.json"
feature_path = "../test/python/results_feature.json"
compare(baseline_path, feature_path)
```

Note that the method offers several parameters to customize the comparison. See {py:func}`mqt.core.evaluation.compare`.
Note that the method offers several parameters to customize the comparison. See {py:func}`mqt.core.dd.evaluation.compare`.
An exemplary run adjusting the parameters is shown below.

```{code-cell} ipython3
Expand All @@ -72,13 +72,13 @@ In an even simpler fashion, the comparison can be run from the command line via
Examples of such runs are shown below.

```{code-cell} ipython3
! mqt-core-compare ../test/python/results_baseline.json ../test/python/results_feature.json --factor=0.2 --only_changed
! mqt-core-dd-compare ../test/python/results_baseline.json ../test/python/results_feature.json --factor=0.2 --only_changed
```

```{code-cell} ipython3
! mqt-core-compare ../test/python/results_baseline.json ../test/python/results_feature.json --no_split --dd --task=functionality
! mqt-core-dd-compare ../test/python/results_baseline.json ../test/python/results_feature.json --no_split --dd --task=functionality
```

```{code-cell} ipython3
! mqt-core-compare ../test/python/results_baseline.json ../test/python/results_feature.json --dd --algorithm=bv --num_qubits=1024
! mqt-core-dd-compare ../test/python/results_baseline.json ../test/python/results_feature.json --dd --algorithm=bv --num_qubits=1024
```
40 changes: 20 additions & 20 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ mystnb:

# Quickstart

The central interface for working with quantum circuits in the Munich Quantum Toolkit is the {py:class}`~mqt.core.QuantumComputation` class.
The central interface for working with quantum circuits in the Munich Quantum Toolkit is the {py:class}`~mqt.core.ir.QuantumComputation` class.
It represents quantum circuits as a sequential list of operations.
Operations can be directly applied to the {py:class}`~mqt.core.QuantumComputation`:
Operations can be directly applied to the {py:class}`~mqt.core.ir.QuantumComputation`:

```{code-cell} ipython3
from mqt.core import QuantumComputation
Expand All @@ -34,7 +34,7 @@ print(qc.qasm3_str())
The circuit class provides a lot of flexibility as every unitary gate can be declared as a controlled gate:

```{code-cell} ipython3
from mqt.core.operations import Control
from mqt.core.ir.operations import Control
nqubits = 2
qc = QuantumComputation(nqubits)
Expand Down Expand Up @@ -65,10 +65,10 @@ print(qc.qasm3_str())

## Layout Information

A {py:class}`~mqt.core.QuantumComputation` also contains information about the mapping of algorithmic (or logical/virtual/circuit) qubits to and from device (or physical) qubits.
These are contained in the {py:attr}`~mqt.core.QuantumComputation.initial_layout` and {py:attr}`~mqt.core.QuantumComputation.output_permutation` members which are instances of the {py:class}`~mqt.core.Permutation` class. If no layout is given the trivial layout is assumed.
A {py:class}`~mqt.core.ir.QuantumComputation` also contains information about the mapping of algorithmic (or logical/virtual/circuit) qubits to and from device (or physical) qubits.
These are contained in the {py:attr}`~mqt.core.ir.QuantumComputation.initial_layout` and {py:attr}`~mqt.core.ir.QuantumComputation.output_permutation` members which are instances of the {py:class}`~mqt.core.ir.Permutation` class. If no layout is given the trivial layout is assumed.

When printing the OpenQASM representation of the {py:class}`~mqt.core.QuantumComputation` the input and output permutations are given as comments in the first two lines of the QASM string. The format is:
When printing the OpenQASM representation of the {py:class}`~mqt.core.ir.QuantumComputation` the input and output permutations are given as comments in the first two lines of the QASM string. The format is:

`// i Q_0, Q_1, ..., Q_n` ... algorithmic qubit $i$ is mapped to device qubit $Q_i$.

Expand All @@ -90,7 +90,7 @@ print(qc.qasm3_str())
```

The layout information can also be automatically determined from measurements
using the {py:meth}`~mqt.core.QuantumComputation.initialize_io_mapping` method:
using the {py:meth}`~mqt.core.ir.QuantumComputation.initialize_io_mapping` method:

```{code-cell} ipython3
nqubits = 3
Expand Down Expand Up @@ -126,19 +126,19 @@ print(qc)

## Operations

The operations in a {py:class}`~mqt.core.QuantumComputation` object are of type {py:class}`~mqt.core.operations.Operation`.
The operations in a {py:class}`~mqt.core.ir.QuantumComputation` object are of type {py:class}`~mqt.core.ir.operations.Operation`.
Every type of operation in `mqt-core` is derived from this class.
Operations can also be explicitly constructed.
Each {py:class}`~mqt.core.operations.Operation` has a type in the form of an {py:class}`~mqt.core.operations.OpType`.
Each {py:class}`~mqt.core.ir.operations.Operation` has a type in the form of an {py:class}`~mqt.core.ir.operations.OpType`.

### `StandardOperation`

A {py:class}`~mqt.core.operations.StandardOperation` is used to represent basic unitary gates. These can also be declared with arbitrary targets and controls.
A {py:class}`~mqt.core.ir.operations.StandardOperation` is used to represent basic unitary gates. These can also be declared with arbitrary targets and controls.

```{code-cell} ipython3
from math import pi
from mqt.core.operations import OpType, StandardOperation
from mqt.core.ir.operations import OpType, StandardOperation
nqubits = 3
Expand All @@ -162,10 +162,10 @@ print(qc)

### `NonUnitaryOperation`

A {py:class}`~mqt.core.operations.NonUnitaryOperation` is used to represent operations involving measurements or resets.
A {py:class}`~mqt.core.ir.operations.NonUnitaryOperation` is used to represent operations involving measurements or resets.

```{code-cell} ipython3
from mqt.core.operations import NonUnitaryOperation
from mqt.core.ir.operations import NonUnitaryOperation
nqubits = 2
qc = QuantumComputation(nqubits, nqubits)
Expand All @@ -185,12 +185,12 @@ print(qc.qasm3_str())

### `SymbolicOperation`

A {py:class}`~mqt.core.operations.SymbolicOperation` can represent all gates of a {py:class}`~mqt.core.operations.StandardOperation` but the gate parameters can be symbolic.
Symbolic expressions are represented in MQT using the {py:class}`~mqt.core.symbolic.Expression` type, which represent linear combinations of symbolic {py:class}`~mqt.core.symbolic.Term` objects over some set of {py:class}`~mqt.core.symbolic.Variable` objects.
A {py:class}`~mqt.core.ir.operations.SymbolicOperation` can represent all gates of a {py:class}`~mqt.core.ir.operations.StandardOperation` but the gate parameters can be symbolic.
Symbolic expressions are represented in MQT using the {py:class}`~mqt.core.ir.symbolic.Expression` type, which represent linear combinations of symbolic {py:class}`~mqt.core.ir.symbolic.Term` objects over some set of {py:class}`~mqt.core.ir.symbolic.Variable` objects.

```{code-cell} ipython3
from mqt.core.operations import SymbolicOperation
from mqt.core.symbolic import Expression, Term, Variable
from mqt.core.ir.operations import SymbolicOperation
from mqt.core.ir.symbolic import Expression, Term, Variable
nqubits = 1
Expand All @@ -211,10 +211,10 @@ u2_symb = SymbolicOperation(target=0, params=[sym, 2.0], op_type=OpType.u2)

### `CompoundOperation`

A {py:class}`~mqt.core.operations.CompoundOperation` bundles multiple {py:class}`~mqt.core.operations.Operation` objects together.
A {py:class}`~mqt.core.ir.operations.CompoundOperation` bundles multiple {py:class}`~mqt.core.ir.operations.Operation` objects together.

```{code-cell} ipython3
from mqt.core.operations import CompoundOperation
from mqt.core.ir.operations import CompoundOperation
nqubits = 2
comp_op = CompoundOperation()
Expand Down Expand Up @@ -247,7 +247,7 @@ print(qc)

## Interfacing with other SDKs

Since a {py:class}`~mqt.core.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.QuantumComputation` class.
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.

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

Expand Down
3 changes: 2 additions & 1 deletion eval/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_executable(mqt-core-dd-eval eval_dd_package.cpp)
target_link_libraries(mqt-core-dd-eval PRIVATE MQT::CoreDD MQT::ProjectOptions MQT::ProjectWarnings)
target_link_libraries(mqt-core-dd-eval PRIVATE MQT::CoreDD MQT::CoreAlgo MQT::CoreCircuitOptimizer
MQT::ProjectOptions MQT::ProjectWarnings)
2 changes: 1 addition & 1 deletion eval/eval_dd_package.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "CircuitOptimizer.hpp"
#include "algorithms/BernsteinVazirani.hpp"
#include "algorithms/Entanglement.hpp"
#include "algorithms/Grover.hpp"
#include "algorithms/QFT.hpp"
#include "algorithms/QPE.hpp"
#include "algorithms/RandomCliffordCircuit.hpp"
#include "algorithms/WState.hpp"
#include "circuit_optimizer/CircuitOptimizer.hpp"
#include "dd/Benchmark.hpp"
#include "dd/FunctionalityConstruction.hpp"
#include "dd/Package.hpp"
Expand Down
10 changes: 1 addition & 9 deletions include/mqt-core/Definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,7 @@ static constexpr size_t OUTPUT_INDENT_SIZE = 2;
class Operation;

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

using DAG = std::vector<std::deque<std::unique_ptr<Operation>*>>;
using DAGIterator = std::deque<std::unique_ptr<Operation>*>::iterator;
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/algorithms/BernsteinVazirani.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "Definitions.hpp"
#include "QuantumComputation.hpp"
#include "ir/QuantumComputation.hpp"

#include <cstddef>
#include <ostream>
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/algorithms/Entanglement.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "QuantumComputation.hpp"
#include "ir/QuantumComputation.hpp"

#include <cstddef>

Expand Down
62 changes: 0 additions & 62 deletions include/mqt-core/algorithms/GoogleRandomCircuitSampling.hpp

This file was deleted.

2 changes: 1 addition & 1 deletion include/mqt-core/algorithms/Grover.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "Definitions.hpp"
#include "QuantumComputation.hpp"
#include "ir/QuantumComputation.hpp"

#include <cstddef>
#include <ostream>
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/algorithms/QFT.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include "QuantumComputation.hpp"
#include "ir/QuantumComputation.hpp"

#include <cstddef>
#include <ostream>
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/algorithms/QPE.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "Definitions.hpp"
#include "QuantumComputation.hpp"
#include "ir/QuantumComputation.hpp"

#include <cstddef>
#include <ostream>
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/algorithms/RandomCliffordCircuit.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "Definitions.hpp"
#include "QuantumComputation.hpp"
#include "ir/QuantumComputation.hpp"

#include <cstddef>
#include <cstdint>
Expand Down
2 changes: 1 addition & 1 deletion include/mqt-core/algorithms/WState.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "Definitions.hpp"
#include "QuantumComputation.hpp"
#include "ir/QuantumComputation.hpp"

namespace qc {
class WState : public QuantumComputation {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#pragma once

#include "Definitions.hpp"
#include "QuantumComputation.hpp"
#include "operations/OpType.hpp"
#include "operations/Operation.hpp"
#include "ir/QuantumComputation.hpp"
#include "ir/operations/OpType.hpp"
#include "ir/operations/Operation.hpp"

#include <cstddef>
#include <memory>
Expand Down Expand Up @@ -49,8 +49,6 @@ class CircuitOptimizer {

static bool isDynamicCircuit(QuantumComputation& qc);

static void reorderOperations(QuantumComputation& qc);

static void flattenOperations(QuantumComputation& qc,
bool customGatesOnly = false);

Expand Down
6 changes: 3 additions & 3 deletions include/mqt-core/datastructures/Layer.hpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#pragma once

#include "Definitions.hpp"
#include "QuantumComputation.hpp"
#include "datastructures/UndirectedGraph.hpp"
#include "operations/OpType.hpp"
#include "operations/Operation.hpp"
#include "ir/QuantumComputation.hpp"
#include "ir/operations/OpType.hpp"
#include "ir/operations/Operation.hpp"

#include <cassert>
#include <cstddef>
Expand Down
Loading

0 comments on commit b16e6e9

Please sign in to comment.