From 3c0799156198bf19b64c1275880558e301543ec8 Mon Sep 17 00:00:00 2001 From: Lukas Burgholzer Date: Tue, 26 Mar 2024 14:59:32 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Eliminate=20`nqubits`=20an?= =?UTF-8?q?d=20`startingQubit`=20from=20`Operation`=20class=20hierarchy=20?= =?UTF-8?q?(#574)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description The third follow-up PRs to #358, which tries to simplify the `Operation` class hierarchy by eliminating the `nqubits` and `startingQubit` members, which were purely in place for managing the corresponding decision diagrams. This also practically fixes #345. Only state creation routines now have the additional starting qubit parameter. ## Checklist: - [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. --------- Signed-off-by: burgholzer --- docs/quickstart.ipynb | 20 +-- eval/CMakeLists.txt | 4 +- include/mqt-core/QuantumComputation.hpp | 54 ++++--- include/mqt-core/dd/Operations.hpp | 14 -- include/mqt-core/ecc/Ecc.hpp | 4 +- .../operations/ClassicControlledOperation.hpp | 6 - .../mqt-core/operations/CompoundOperation.hpp | 11 +- .../operations/NonUnitaryOperation.hpp | 18 ++- include/mqt-core/operations/Operation.hpp | 19 +-- .../mqt-core/operations/StandardOperation.hpp | 41 ++--- .../mqt-core/operations/SymbolicOperation.hpp | 43 +++--- src/CircuitOptimizer.cpp | 124 ++++++--------- src/QuantumComputation.cpp | 35 +---- .../GoogleRandomCircuitSampling.cpp | 19 ++- src/dd/Operations.cpp | 7 - src/dd/Simulation.cpp | 4 +- src/ecc/Q3Shor.cpp | 15 +- src/ecc/Q5Laflamme.cpp | 3 +- src/ecc/Q7Steane.cpp | 22 +-- src/ecc/Q9Shor.cpp | 5 +- src/mqt/core/_core/operations.pyi | 41 +---- src/mqt/core/io.py | 4 +- src/mqt/core/plugins/qiskit.py | 16 +- src/operations/CompoundOperation.cpp | 19 +-- src/operations/NonUnitaryOperation.cpp | 34 ++--- src/operations/Operation.cpp | 6 +- src/operations/StandardOperation.cpp | 68 +++------ src/operations/SymbolicOperation.cpp | 70 ++++----- src/parsers/QASM3Parser.cpp | 27 ++-- src/parsers/QCParser.cpp | 4 +- src/parsers/RealParser.cpp | 7 +- .../register_compound_operation.cpp | 12 +- .../register_non_unitary_operation.cpp | 16 +- src/python/operations/register_operation.cpp | 10 +- .../register_standard_operation.cpp | 57 +++---- .../register_symbolic_operation.cpp | 51 +++---- src/python/qiskit/QuantumCircuit.cpp | 26 ++-- test/dd/test_dd_functionality.cpp | 58 ++++--- test/dd/test_dd_noise_functionality.cpp | 15 +- test/python/test_qiskit.py | 9 -- test/unittests/test_ecc_functionality.cpp | 3 +- test/unittests/test_io.cpp | 2 +- test/unittests/test_qfr_functionality.cpp | 143 ++++++------------ test/zx/test_zx_functionality.cpp | 6 +- 44 files changed, 438 insertions(+), 734 deletions(-) diff --git a/docs/quickstart.ipynb b/docs/quickstart.ipynb index 40234bdf3..02c637e50 100644 --- a/docs/quickstart.ipynb +++ b/docs/quickstart.ipynb @@ -209,13 +209,13 @@ "nqubits = 3\n", "\n", "# u3 gate on qubit 0 in a 3-qubit circuit\n", - "u_gate = StandardOperation(nqubits, target=0, params=[pi / 4, pi, -pi / 2], op_type=OpType.u)\n", + "u_gate = StandardOperation(target=0, params=[pi / 4, pi, -pi / 2], op_type=OpType.u)\n", "\n", "# controlled x-rotation\n", - "crx = StandardOperation(nqubits, control=Control(0), target=1, params=[pi], op_type=OpType.rx)\n", + "crx = StandardOperation(control=Control(0), target=1, params=[pi], op_type=OpType.rx)\n", "\n", "# multi-controlled x-gate\n", - "mcx = StandardOperation(nqubits, controls={Control(0), Control(1)}, target=2, op_type=OpType.x)\n", + "mcx = StandardOperation(controls={Control(0), Control(1)}, target=2, op_type=OpType.x)\n", "\n", "# add operations to a quantum computation\n", "qc = QuantumComputation(nqubits)\n", @@ -250,10 +250,10 @@ "qc.h(0)\n", "\n", "# measure qubit 0 on classical bit 0\n", - "meas_0 = NonUnitaryOperation(nqubits, target=0, classic=0)\n", + "meas_0 = NonUnitaryOperation(target=0, classic=0)\n", "\n", "# reset all qubits\n", - "reset = NonUnitaryOperation(nqubits, targets=[0, 1], op_type=OpType.reset)\n", + "reset = NonUnitaryOperation(targets=[0, 1], op_type=OpType.reset)\n", "\n", "qc.append(meas_0)\n", "qc.append(reset)\n", @@ -293,10 +293,10 @@ "print(sym)\n", "\n", "# Create symbolic gate\n", - "u1_symb = SymbolicOperation(nqubits, target=0, params=[sym], op_type=OpType.p)\n", + "u1_symb = SymbolicOperation(target=0, params=[sym], op_type=OpType.p)\n", "\n", "# Mixed symbolic and instantiated parameters\n", - "u2_symb = SymbolicOperation(nqubits, target=0, params=[sym, 2.0], op_type=OpType.u2)" + "u2_symb = SymbolicOperation(target=0, params=[sym, 2.0], op_type=OpType.u2)" ] }, { @@ -319,11 +319,11 @@ "from mqt.core.operations import CompoundOperation\n", "\n", "nqubits = 2\n", - "comp_op = CompoundOperation(nqubits)\n", + "comp_op = CompoundOperation()\n", "\n", "# create bell pair circuit\n", - "comp_op.append(StandardOperation(nqubits, 0, op_type=OpType.h))\n", - "comp_op.append(StandardOperation(nqubits, target=0, control=Control(1), op_type=OpType.x))\n", + "comp_op.append(StandardOperation(0, op_type=OpType.h))\n", + "comp_op.append(StandardOperation(target=0, control=Control(1), op_type=OpType.x))\n", "\n", "qc = QuantumComputation(nqubits)\n", "qc.append(comp_op)\n", diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt index e378a0eec..6db8f1270 100644 --- a/eval/CMakeLists.txt +++ b/eval/CMakeLists.txt @@ -1,2 +1,2 @@ -add_executable(${PROJECT_NAME}-dd-eval eval_dd_package.cpp) -target_link_libraries(${PROJECT_NAME}-dd-eval ${PROJECT_NAME}-dd) +add_executable(mqt-core-dd-eval eval_dd_package.cpp) +target_link_libraries(mqt-core-dd-eval PRIVATE MQT::CoreDD MQT::ProjectOptions MQT::ProjectWarnings) diff --git a/include/mqt-core/QuantumComputation.hpp b/include/mqt-core/QuantumComputation.hpp index c2d86408e..293e34399 100644 --- a/include/mqt-core/QuantumComputation.hpp +++ b/include/mqt-core/QuantumComputation.hpp @@ -434,7 +434,7 @@ class QuantumComputation { } \ void mc##op(const Controls& controls, const Qubit target) { \ checkQubitRange(target, controls); \ - emplace_back(getNqubits(), controls, target, \ + emplace_back(controls, target, \ OP_NAME_TO_TYPE.at(#op)); \ } @@ -464,14 +464,13 @@ class QuantumComputation { const Qubit target) { \ checkQubitRange(target, controls); \ if (std::holds_alternative(param)) { \ - emplace_back(getNqubits(), controls, target, \ + emplace_back(controls, target, \ OP_NAME_TO_TYPE.at(#op), \ std::vector{std::get(param)}); \ } else { \ addVariables(param); \ - emplace_back(getNqubits(), controls, target, \ - OP_NAME_TO_TYPE.at(#op), \ - std::vector{param}); \ + emplace_back( \ + controls, target, OP_NAME_TO_TYPE.at(#op), std::vector{param}); \ } \ } @@ -495,11 +494,11 @@ class QuantumComputation { if (std::holds_alternative(param0) && \ std::holds_alternative(param1)) { \ emplace_back( \ - getNqubits(), controls, target, OP_NAME_TO_TYPE.at(#op), \ + controls, target, OP_NAME_TO_TYPE.at(#op), \ std::vector{std::get(param0), std::get(param1)}); \ } else { \ addVariables(param0, param1); \ - emplace_back(getNqubits(), controls, target, \ + emplace_back(controls, target, \ OP_NAME_TO_TYPE.at(#op), \ std::vector{param0, param1}); \ } \ @@ -526,12 +525,12 @@ class QuantumComputation { std::holds_alternative(param1) && \ std::holds_alternative(param2)) { \ emplace_back( \ - getNqubits(), controls, target, OP_NAME_TO_TYPE.at(#op), \ + controls, target, OP_NAME_TO_TYPE.at(#op), \ std::vector{std::get(param0), std::get(param1), \ std::get(param2)}); \ } else { \ addVariables(param0, param1, param2); \ - emplace_back(getNqubits(), controls, target, \ + emplace_back(controls, target, \ OP_NAME_TO_TYPE.at(#op), \ std::vector{param0, param1, param2}); \ } \ @@ -550,7 +549,7 @@ class QuantumComputation { void mc##op(const Controls& controls, const Qubit target0, \ const Qubit target1) { \ checkQubitRange(target0, target1, controls); \ - emplace_back(getNqubits(), controls, target0, target1, \ + emplace_back(controls, target0, target1, \ OP_NAME_TO_TYPE.at(#op)); \ } @@ -575,13 +574,13 @@ class QuantumComputation { const Qubit target0, const Qubit target1) { \ checkQubitRange(target0, target1, controls); \ if (std::holds_alternative(param)) { \ - emplace_back(getNqubits(), controls, target0, \ - target1, OP_NAME_TO_TYPE.at(#op), \ + emplace_back(controls, target0, target1, \ + OP_NAME_TO_TYPE.at(#op), \ std::vector{std::get(param)}); \ } else { \ addVariables(param); \ - emplace_back(getNqubits(), controls, target0, \ - target1, OP_NAME_TO_TYPE.at(#op), \ + emplace_back(controls, target0, target1, \ + OP_NAME_TO_TYPE.at(#op), \ std::vector{param}); \ } \ } @@ -608,12 +607,12 @@ class QuantumComputation { if (std::holds_alternative(param0) && \ std::holds_alternative(param1)) { \ emplace_back( \ - getNqubits(), controls, target0, target1, OP_NAME_TO_TYPE.at(#op), \ + controls, target0, target1, OP_NAME_TO_TYPE.at(#op), \ std::vector{std::get(param0), std::get(param1)}); \ } else { \ addVariables(param0, param1); \ - emplace_back(getNqubits(), controls, target0, \ - target1, OP_NAME_TO_TYPE.at(#op), \ + emplace_back(controls, target0, target1, \ + OP_NAME_TO_TYPE.at(#op), \ std::vector{param0, param1}); \ } \ } @@ -632,7 +631,7 @@ class QuantumComputation { void measure(const Qubit qubit, const std::size_t bit) { checkQubitRange(qubit); checkBitRange(bit); - emplace_back(getNqubits(), qubit, bit); + emplace_back(qubit, bit); } void measure(Qubit qubit, const std::pair& registerBit); @@ -640,7 +639,7 @@ class QuantumComputation { void measure(const Targets& qubits, const std::vector& bits) { checkQubitRange(qubits); checkBitRange(bits); - emplace_back(getNqubits(), qubits, bits); + emplace_back(qubits, bits); } /** @@ -654,26 +653,25 @@ class QuantumComputation { void reset(const Qubit target) { checkQubitRange(target); - emplace_back(getNqubits(), std::vector{target}, - qc::Reset); + emplace_back(std::vector{target}, qc::Reset); } void reset(const Targets& targets) { checkQubitRange(targets); - emplace_back(getNqubits(), targets, qc::Reset); + emplace_back(targets, qc::Reset); } void barrier() { std::vector targets(getNqubits()); std::iota(targets.begin(), targets.end(), 0); - emplace_back(getNqubits(), targets, qc::Barrier); + emplace_back(targets, qc::Barrier); } void barrier(const Qubit target) { checkQubitRange(target); - emplace_back(getNqubits(), target, qc::Barrier); + emplace_back(target, qc::Barrier); } void barrier(const Targets& targets) { checkQubitRange(targets); - emplace_back(getNqubits(), targets, qc::Barrier); + emplace_back(targets, qc::Barrier); } void classicControlled(const OpType op, const Qubit target, @@ -698,8 +696,8 @@ class QuantumComputation { const std::vector& params = {}) { checkQubitRange(target, controls); checkClassicalRegister(controlRegister); - std::unique_ptr gate = std::make_unique( - getNqubits(), controls, target, op, params); + std::unique_ptr gate = + std::make_unique(controls, target, op, params); emplace_back(std::move(gate), controlRegister, expectedValue); } @@ -844,7 +842,7 @@ class QuantumComputation { // this convenience method allows to turn a circuit into a compound operation. std::unique_ptr asCompoundOperation() { - return std::make_unique(getNqubits(), std::move(ops)); + return std::make_unique(std::move(ops)); } // this convenience method allows to turn a circuit into an operation. diff --git a/include/mqt-core/dd/Operations.hpp b/include/mqt-core/dd/Operations.hpp index 40079d20f..468d935d3 100644 --- a/include/mqt-core/dd/Operations.hpp +++ b/include/mqt-core/dd/Operations.hpp @@ -164,20 +164,6 @@ template qc::MatrixDD getDD(const qc::Operation* op, Package& dd, qc::Permutation& permutation, const bool inverse = false) { const auto type = op->getType(); - const auto nqubits = op->getNqubits(); - - // check whether the operation can be handled by the underlying DD package - if (nqubits > Package::MAX_POSSIBLE_QUBITS) { - throw qc::QFRException( - "Requested too many qubits to be handled by the DD package. Qubit " - "datatype only allows up to " + - std::to_string(Package::MAX_POSSIBLE_QUBITS) + - " qubits, while " + std::to_string(nqubits) + - " were requested. If you want to use more than " + - std::to_string(Package::MAX_POSSIBLE_QUBITS) + - " qubits, you have to recompile the package with a wider Qubit type in " - "`include/dd/DDDefinitions.hpp!`"); - } // if a permutation is provided and the current operation is a SWAP, this // routine just updates the permutation diff --git a/include/mqt-core/ecc/Ecc.hpp b/include/mqt-core/ecc/Ecc.hpp index 85ebceaa4..21ea6f5dc 100644 --- a/include/mqt-core/ecc/Ecc.hpp +++ b/include/mqt-core/ecc/Ecc.hpp @@ -103,8 +103,8 @@ class Ecc { void gateNotAvailableError(const qc::Operation& gate) const { std::stringstream stream; - stream << "Gate " << gate << " not supported to encode in error code " - << ecc.name << "!"; + stream << "Gate " << toString(gate.getType()) + << " not supported to encode in error code " << ecc.name << "!"; throw qc::QFRException(stream.str()); } }; diff --git a/include/mqt-core/operations/ClassicControlledOperation.hpp b/include/mqt-core/operations/ClassicControlledOperation.hpp index f6d730fdc..f31c3cecb 100644 --- a/include/mqt-core/operations/ClassicControlledOperation.hpp +++ b/include/mqt-core/operations/ClassicControlledOperation.hpp @@ -37,7 +37,6 @@ class ClassicControlledOperation final : public Operation { ComparisonKind kind = ComparisonKind::Eq) : op(std::move(operation)), controlRegister(std::move(controlReg)), expectedValue(expectedVal), comparisonKind(kind) { - nqubits = op->getNqubits(); name = "c_" + shortName(op->getType()); parameter.reserve(3); parameter.emplace_back(static_cast(controlRegister.first)); @@ -73,11 +72,6 @@ class ClassicControlledOperation final : public Operation { [[nodiscard]] auto getOperation() const { return op.get(); } - void setNqubits(std::size_t nq) override { - nqubits = nq; - op->setNqubits(nq); - } - [[nodiscard]] const Targets& getTargets() const override { return op->getTargets(); } diff --git a/include/mqt-core/operations/CompoundOperation.hpp b/include/mqt-core/operations/CompoundOperation.hpp index f8764fe82..a25dc54d0 100644 --- a/include/mqt-core/operations/CompoundOperation.hpp +++ b/include/mqt-core/operations/CompoundOperation.hpp @@ -9,10 +9,10 @@ class CompoundOperation final : public Operation { std::vector> ops{}; public: - explicit CompoundOperation(std::size_t nq); + explicit CompoundOperation(); - CompoundOperation(std::size_t nq, - std::vector>&& operations); + explicit CompoundOperation( + std::vector>&& operations); CompoundOperation(const CompoundOperation& co); @@ -20,8 +20,6 @@ class CompoundOperation final : public Operation { [[nodiscard]] std::unique_ptr clone() const override; - void setNqubits(std::size_t nq) override; - [[nodiscard]] bool isCompoundOperation() const override; [[nodiscard]] bool isNonUnitaryOperation() const override; @@ -41,7 +39,8 @@ class CompoundOperation final : public Operation { [[nodiscard]] bool equals(const Operation& operation) const override; std::ostream& print(std::ostream& os, const Permutation& permutation, - std::size_t prefixWidth) const override; + std::size_t prefixWidth, + std::size_t nqubits) const override; [[nodiscard]] bool actsOn(Qubit i) const override; diff --git a/include/mqt-core/operations/NonUnitaryOperation.hpp b/include/mqt-core/operations/NonUnitaryOperation.hpp index 78f27e70a..7a130e6ca 100644 --- a/include/mqt-core/operations/NonUnitaryOperation.hpp +++ b/include/mqt-core/operations/NonUnitaryOperation.hpp @@ -8,20 +8,21 @@ class NonUnitaryOperation final : public Operation { protected: std::vector classics{}; // vector for the classical bits to measure into - void printMeasurement(std::ostream& os, const std::vector& q, - const std::vector& c, - const Permutation& permutation) const; + static void printMeasurement(std::ostream& os, const std::vector& q, + const std::vector& c, + const Permutation& permutation, + std::size_t nqubits); void printReset(std::ostream& os, const std::vector& q, - const Permutation& permutation) const; + const Permutation& permutation, std::size_t nqubits) const; public: // Measurement constructor - NonUnitaryOperation(std::size_t nq, std::vector qubitRegister, + NonUnitaryOperation(std::vector qubitRegister, std::vector classicalRegister); - NonUnitaryOperation(std::size_t nq, Qubit qubit, Bit cbit); + NonUnitaryOperation(Qubit qubit, Bit cbit); // General constructor - NonUnitaryOperation(std::size_t nq, Targets qubits, OpType op = Reset); + explicit NonUnitaryOperation(Targets qubits, OpType op = Reset); [[nodiscard]] std::unique_ptr clone() const override { return std::make_unique(*this); @@ -73,7 +74,8 @@ class NonUnitaryOperation final : public Operation { } std::ostream& print(std::ostream& os, const Permutation& permutation, - std::size_t prefixWidth) const override; + std::size_t prefixWidth, + std::size_t nqubits) const override; void dumpOpenQASM(std::ostream& of, const RegisterNames& qreg, const RegisterNames& creg, size_t indent, diff --git a/include/mqt-core/operations/Operation.hpp b/include/mqt-core/operations/Operation.hpp index 0f537a713..5bf5bc856 100644 --- a/include/mqt-core/operations/Operation.hpp +++ b/include/mqt-core/operations/Operation.hpp @@ -21,8 +21,6 @@ class Operation { Targets targets{}; std::vector parameter{}; - std::size_t nqubits = 0; - Qubit startQubit = 0; OpType type = None; std::string name{}; @@ -58,8 +56,6 @@ class Operation { return controls.size(); } - [[nodiscard]] std::size_t getNqubits() const { return nqubits; } - [[nodiscard]] const std::vector& getParameter() const { return parameter; } @@ -68,8 +64,6 @@ class Operation { [[nodiscard]] const std::string& getName() const { return name; } [[nodiscard]] virtual OpType getType() const { return type; } - [[nodiscard]] virtual Qubit getStartingQubit() const { return startQubit; } - [[nodiscard]] virtual std::set getUsedQubits() const { const auto& opTargets = getTargets(); const auto& opControls = getControls(); @@ -87,8 +81,6 @@ class Operation { } // Setter - virtual void setNqubits(const std::size_t nq) { nqubits = nq; } - virtual void setTargets(const Targets& t) { targets = t; } virtual void setControls(const Controls& c) { @@ -168,13 +160,12 @@ class Operation { } virtual std::ostream& printParameters(std::ostream& os) const; - std::ostream& print(std::ostream& os) const { return print(os, {}, 0); } - virtual std::ostream& print(std::ostream& os, const Permutation& permutation, - std::size_t prefixWidth) const; - - friend std::ostream& operator<<(std::ostream& os, const Operation& op) { - return op.print(os); + std::ostream& print(std::ostream& os, const std::size_t nqubits) const { + return print(os, {}, 0, nqubits); } + virtual std::ostream& print(std::ostream& os, const Permutation& permutation, + std::size_t prefixWidth, + std::size_t nqubits) const; void dumpOpenQASM2(std::ostream& of, const RegisterNames& qreg, const RegisterNames& creg) const { diff --git a/include/mqt-core/operations/StandardOperation.hpp b/include/mqt-core/operations/StandardOperation.hpp index 47209b287..578f9a639 100644 --- a/include/mqt-core/operations/StandardOperation.hpp +++ b/include/mqt-core/operations/StandardOperation.hpp @@ -27,7 +27,7 @@ class StandardOperation : public Operation { OpType parseU1(fp& lambda); void checkUgate(); - void setup(std::size_t nq, Qubit startingQubit = 0); + void setup(); void dumpOpenQASMTeleportation(std::ostream& of, const RegisterNames& qreg) const; @@ -36,33 +36,22 @@ class StandardOperation : public Operation { StandardOperation() = default; // Standard Constructors - StandardOperation(std::size_t nq, Qubit target, OpType g, - std::vector params = {}, Qubit startingQubit = 0); - StandardOperation(std::size_t nq, const Targets& targ, OpType g, - std::vector params = {}, Qubit startingQubit = 0); - - StandardOperation(std::size_t nq, Control control, Qubit target, OpType g, - const std::vector& params = {}, - Qubit startingQubit = 0); - StandardOperation(std::size_t nq, Control control, const Targets& targ, - OpType g, const std::vector& params = {}, - Qubit startingQubit = 0); - - StandardOperation(std::size_t nq, const Controls& c, Qubit target, OpType g, - const std::vector& params = {}, - Qubit startingQubit = 0); - StandardOperation(std::size_t nq, const Controls& c, const Targets& targ, - OpType g, const std::vector& params = {}, - Qubit startingQubit = 0); - - // MCT Constructor - StandardOperation(std::size_t nq, const Controls& c, Qubit target, - Qubit startingQubit = 0); + StandardOperation(Qubit target, OpType g, std::vector params = {}); + StandardOperation(const Targets& targ, OpType g, std::vector params = {}); + + StandardOperation(Control control, Qubit target, OpType g, + const std::vector& params = {}); + StandardOperation(Control control, const Targets& targ, OpType g, + const std::vector& params = {}); + + StandardOperation(const Controls& c, Qubit target, OpType g, + const std::vector& params = {}); + StandardOperation(const Controls& c, const Targets& targ, OpType g, + const std::vector& params = {}); // MCF (cSWAP), Peres, parameterized two target Constructor - StandardOperation(std::size_t nq, const Controls& c, Qubit target0, - Qubit target1, OpType g, const std::vector& params = {}, - Qubit startingQubit = 0); + StandardOperation(const Controls& c, Qubit target0, Qubit target1, OpType g, + const std::vector& params = {}); [[nodiscard]] std::unique_ptr clone() const override { return std::make_unique(*this); diff --git a/include/mqt-core/operations/SymbolicOperation.hpp b/include/mqt-core/operations/SymbolicOperation.hpp index e30ee454d..a440e0507 100644 --- a/include/mqt-core/operations/SymbolicOperation.hpp +++ b/include/mqt-core/operations/SymbolicOperation.hpp @@ -59,8 +59,7 @@ class SymbolicOperation final : public StandardOperation { static fp& getNumber(SymbolOrNumber& param) { return std::get(param); } - void setup(std::size_t nq, const std::vector& params, - Qubit startingQubit = 0); + void setup(const std::vector& params); [[nodiscard]] static fp getInstantiation(const SymbolOrNumber& symOrNum, @@ -94,32 +93,24 @@ class SymbolicOperation final : public StandardOperation { } // Standard Constructors - SymbolicOperation(std::size_t nq, Qubit target, OpType g, - const std::vector& params = {}, - Qubit startingQubit = 0); - SymbolicOperation(std::size_t nq, const Targets& targ, OpType g, - const std::vector& params = {}, - Qubit startingQubit = 0); - - SymbolicOperation(std::size_t nq, Control control, Qubit target, OpType g, - const std::vector& params = {}, - Qubit startingQubit = 0); - SymbolicOperation(std::size_t nq, Control control, const Targets& targ, - OpType g, const std::vector& params = {}, - Qubit startingQubit = 0); - - SymbolicOperation(std::size_t nq, const Controls& c, Qubit target, OpType g, - const std::vector& params = {}, - Qubit startingQubit = 0); - SymbolicOperation(std::size_t nq, const Controls& c, const Targets& targ, - OpType g, const std::vector& params = {}, - Qubit startingQubit = 0); + SymbolicOperation(Qubit target, OpType g, + const std::vector& params = {}); + SymbolicOperation(const Targets& targ, OpType g, + const std::vector& params = {}); + + SymbolicOperation(Control control, Qubit target, OpType g, + const std::vector& params = {}); + SymbolicOperation(Control control, const Targets& targ, OpType g, + const std::vector& params = {}); + + SymbolicOperation(const Controls& c, Qubit target, OpType g, + const std::vector& params = {}); + SymbolicOperation(const Controls& c, const Targets& targ, OpType g, + const std::vector& params = {}); // MCF (cSWAP), Peres, parameterized two target Constructor - SymbolicOperation(std::size_t nq, const Controls& c, Qubit target0, - Qubit target1, OpType g, - const std::vector& params = {}, - Qubit startingQubit = 0); + SymbolicOperation(const Controls& c, Qubit target0, Qubit target1, OpType g, + const std::vector& params = {}); [[nodiscard]] std::unique_ptr clone() const override { return std::make_unique(*this); diff --git a/src/CircuitOptimizer.cpp b/src/CircuitOptimizer.cpp index f80ad9f38..82c4f6f18 100644 --- a/src/CircuitOptimizer.cpp +++ b/src/CircuitOptimizer.cpp @@ -1,5 +1,6 @@ #include "CircuitOptimizer.hpp" +#include #include namespace qc { @@ -38,9 +39,7 @@ void CircuitOptimizer::removeIdentities(QuantumComputation& qc) { void CircuitOptimizer::swapReconstruction(QuantumComputation& qc) { Qubit highestPhysicalQubit = 0; for (const auto& q : qc.initialLayout) { - if (q.first > highestPhysicalQubit) { - highestPhysicalQubit = q.first; - } + highestPhysicalQubit = std::max(q.first, highestPhysicalQubit); } auto dag = DAG(highestPhysicalQubit + 1); @@ -126,9 +125,7 @@ void CircuitOptimizer::swapReconstruction(QuantumComputation& qc) { DAG CircuitOptimizer::constructDAG(QuantumComputation& qc) { Qubit highestPhysicalQubit = 0; for (const auto& q : qc.initialLayout) { - if (q.first > highestPhysicalQubit) { - highestPhysicalQubit = q.first; - } + highestPhysicalQubit = std::max(q.first, highestPhysicalQubit); } auto dag = DAG(highestPhysicalQubit + 1); @@ -157,10 +154,9 @@ void CircuitOptimizer::addNonStandardOperationToDag( const auto& gate = *op; // compound operations are added "as-is" if (gate->isCompoundOperation()) { - for (std::size_t i = 0U; i < gate->getNqubits(); ++i) { - if (gate->actsOn(static_cast(i))) { - dag.at(i).push_back(op); - } + const auto usedQubits = gate->getUsedQubits(); + for (const auto q : usedQubits) { + dag.at(q).push_back(op); } } else if (gate->isNonUnitaryOperation()) { for (const auto& b : gate->getTargets()) { @@ -189,9 +185,7 @@ void CircuitOptimizer::singleQubitGateFusion(QuantumComputation& qc) { Qubit highestPhysicalQubit = 0; for (const auto& q : qc.initialLayout) { - if (q.first > highestPhysicalQubit) { - highestPhysicalQubit = q.first; - } + highestPhysicalQubit = std::max(q.first, highestPhysicalQubit); } auto dag = DAG(highestPhysicalQubit + 1); @@ -260,8 +254,7 @@ void CircuitOptimizer::singleQubitGateFusion(QuantumComputation& qc) { it->setGate(qc::I); } else { compop->emplace_back( - it->getNqubits(), it->getTargets().at(0), it->getType(), - it->getParameter()); + it->getTargets().at(0), it->getType(), it->getParameter()); it->setGate(I); } @@ -276,13 +269,11 @@ void CircuitOptimizer::singleQubitGateFusion(QuantumComputation& qc) { (*op)->setGate(qc::I); it->setGate(qc::I); } else { - auto compop = std::make_unique(it->getNqubits()); + auto compop = std::make_unique(); compop->emplace_back( - (*op)->getNqubits(), (*op)->getTargets().at(0), (*op)->getType(), - (*op)->getParameter()); + (*op)->getTargets().at(0), (*op)->getType(), (*op)->getParameter()); compop->emplace_back( - it->getNqubits(), it->getTargets().at(0), it->getType(), - it->getParameter()); + it->getTargets().at(0), it->getType(), it->getParameter()); it->setGate(I); (*op) = std::move(compop); dag.at(target).push_back(op); @@ -601,31 +592,26 @@ void CircuitOptimizer::decomposeSWAP(QuantumComputation& qc, if ((*it)->isStandardOperation()) { if ((*it)->getType() == qc::SWAP) { const auto targets = (*it)->getTargets(); - const auto nqubits = (*it)->getNqubits(); it = qc.ops.erase(it); - it = qc.ops.insert( - it, std::make_unique( - nqubits, Control{targets[0]}, targets[1], qc::X)); + it = qc.ops.insert(it, std::make_unique( + Control{targets[0]}, targets[1], qc::X)); if (isDirectedArchitecture) { - it = qc.ops.insert(it, std::make_unique( - nqubits, targets[0], qc::H)); - it = qc.ops.insert(it, std::make_unique( - nqubits, targets[1], qc::H)); it = qc.ops.insert( - it, std::make_unique( - nqubits, Control{targets[0]}, targets[1], qc::X)); - it = qc.ops.insert(it, std::make_unique( - nqubits, targets[0], qc::H)); + it, std::make_unique(targets[0], qc::H)); + it = qc.ops.insert( + it, std::make_unique(targets[1], qc::H)); it = qc.ops.insert(it, std::make_unique( - nqubits, targets[1], qc::H)); - } else { + Control{targets[0]}, targets[1], qc::X)); it = qc.ops.insert( - it, std::make_unique( - nqubits, Control{targets[1]}, targets[0], qc::X)); + it, std::make_unique(targets[0], qc::H)); + it = qc.ops.insert( + it, std::make_unique(targets[1], qc::H)); + } else { + it = qc.ops.insert(it, std::make_unique( + Control{targets[1]}, targets[0], qc::X)); } - it = qc.ops.insert( - it, std::make_unique( - nqubits, Control{targets[0]}, targets[1], qc::X)); + it = qc.ops.insert(it, std::make_unique( + Control{targets[0]}, targets[1], qc::X)); } else { ++it; } @@ -635,27 +621,22 @@ void CircuitOptimizer::decomposeSWAP(QuantumComputation& qc, while (cit != compOp->end()) { if ((*cit)->isStandardOperation() && (*cit)->getType() == qc::SWAP) { const auto targets = (*cit)->getTargets(); - const auto nqubits = compOp->getNqubits(); cit = compOp->erase(cit); - cit = compOp->insert( - cit, nqubits, Control{targets[0]}, targets[1], qc::X); + cit = compOp->insert(cit, Control{targets[0]}, + targets[1], qc::X); if (isDirectedArchitecture) { - cit = compOp->insert(cit, nqubits, targets[0], - qc::H); - cit = compOp->insert(cit, nqubits, targets[1], - qc::H); - cit = compOp->insert( - cit, nqubits, Control{targets[0]}, targets[1], qc::X); - cit = compOp->insert(cit, nqubits, targets[0], - qc::H); - cit = compOp->insert(cit, nqubits, targets[1], - qc::H); + cit = compOp->insert(cit, targets[0], qc::H); + cit = compOp->insert(cit, targets[1], qc::H); + cit = compOp->insert(cit, Control{targets[0]}, + targets[1], qc::X); + cit = compOp->insert(cit, targets[0], qc::H); + cit = compOp->insert(cit, targets[1], qc::H); } else { - cit = compOp->insert( - cit, nqubits, Control{targets[1]}, targets[0], qc::X); + cit = compOp->insert(cit, Control{targets[1]}, + targets[0], qc::X); } - cit = compOp->insert( - cit, nqubits, Control{targets[0]}, targets[1], qc::X); + cit = compOp->insert(cit, Control{targets[0]}, + targets[1], qc::X); } else { ++cit; } @@ -740,13 +721,6 @@ void CircuitOptimizer::eliminateResets(QuantumComputation& qc) { it++; } } - // if anything has been modified the number of qubits of each gate has to be - // adjusted - if (!replacementMap.empty()) { - for (auto& op : qc.ops) { - op->setNqubits(qc.getNqubits()); - } - } } void CircuitOptimizer::changeTargets( @@ -876,15 +850,13 @@ void CircuitOptimizer::deferMeasurements(QuantumComputation& qc) { std::stringstream ss{}; ss << "Underlying operation of classic-controlled operation is " "not a StandardOperation.\n"; - classicOp->print(ss); + classicOp->print(ss, qc.nqubits); throw QFRException(ss.str()); } // get all the necessary information for reconstructing the // operation - const auto nqubits = standardOp->getNqubits(); const auto type = standardOp->getType(); - const auto targs = standardOp->getTargets(); for (const auto& target : targs) { if (target == measurementQubit) { @@ -925,10 +897,9 @@ void CircuitOptimizer::deferMeasurements(QuantumComputation& qc) { itInvalidated = (it >= currentInsertionPoint); // insert the new operation (invalidated all pointer onwards) - currentInsertionPoint = - qc.insert(currentInsertionPoint, - std::make_unique( - nqubits, controls, targs, type, parameters)); + currentInsertionPoint = qc.insert( + currentInsertionPoint, std::make_unique( + controls, targs, type, parameters)); if (itInvalidated) { it = currentInsertionPoint; @@ -1202,9 +1173,7 @@ CircuitOptimizer::Iterator CircuitOptimizer::flattenCompoundOperation( void CircuitOptimizer::cancelCNOTs(QuantumComputation& qc) { Qubit highestPhysicalQubit = 0; for (const auto& q : qc.initialLayout) { - if (q.first > highestPhysicalQubit) { - highestPhysicalQubit = q.first; - } + highestPhysicalQubit = std::max(q.first, highestPhysicalQubit); } auto dag = DAG(highestPhysicalQubit + 1U); @@ -1375,18 +1344,15 @@ void CircuitOptimizer::replaceMCXWithMCZ( const auto& controls = op->getControls(); assert(op->getNtargets() == 1U); const auto target = op->getTargets()[0]; - const auto nqubits = op->getNqubits(); // -c- ---c--- // | = | // -X- -H-Z-H- std::array, 3U> replacementOps{}; - replacementOps[0] = - std::make_unique(nqubits, target, H); + replacementOps[0] = std::make_unique(target, H); replacementOps[1] = - std::make_unique(nqubits, controls, target, Z); - replacementOps[2] = - std::make_unique(nqubits, target, H); + std::make_unique(controls, target, Z); + replacementOps[2] = std::make_unique(target, H); it = ops.insert(it, std::make_move_iterator(replacementOps.begin()), std::make_move_iterator(replacementOps.end())); diff --git a/src/QuantumComputation.cpp b/src/QuantumComputation.cpp index b68326124..a08ceba30 100644 --- a/src/QuantumComputation.cpp +++ b/src/QuantumComputation.cpp @@ -246,11 +246,6 @@ void QuantumComputation::addQubitRegister(std::size_t nq, outputPermutation.insert({j, j}); } nqubits += nq; - - for (auto& op : ops) { - op->setNqubits(nqubits + nancillae); - } - ancillary.resize(nqubits + nancillae); garbage.resize(nqubits + nancillae); } @@ -295,10 +290,6 @@ void QuantumComputation::addAncillaryRegister(std::size_t nq, ancillary[j] = true; } nancillae += nq; - - for (auto& op : ops) { - op->setNqubits(nqubits + nancillae); - } } void QuantumComputation::removeQubitfromQubitRegister(QuantumRegisterMap& regs, @@ -403,13 +394,8 @@ QuantumComputation::removeQubit(const Qubit logicalQubitIndex) { outputPermutation.erase(physicalQubitIndex); } - // update all operations - const auto totalQubits = nqubits + nancillae; - for (auto& op : ops) { - op->setNqubits(totalQubits); - } - // update ancillary and garbage tracking + const auto totalQubits = nqubits + nancillae; for (std::size_t i = logicalQubitIndex; i < totalQubits; ++i) { ancillary[i] = ancillary[i + 1]; garbage[i] = garbage[i + 1]; @@ -455,11 +441,6 @@ void QuantumComputation::addAncillaryQubit( // if a qubit is not relevant for the output, it is considered garbage garbage[logicalQubitIndex] = true; } - - // update all operations - for (auto& op : ops) { - op->setNqubits(nqubits + nancillae); - } } void QuantumComputation::addQubit(const Qubit logicalQubitIndex, @@ -491,14 +472,8 @@ void QuantumComputation::addQubit(const Qubit logicalQubitIndex, outputPermutation.insert({physicalQubitIndex, *outputQubitIndex}); } - const auto totalQubits = nqubits + nancillae; - - // update all operations - for (auto& op : ops) { - op->setNqubits(totalQubits); - } - // update ancillary and garbage tracking + const auto totalQubits = nqubits + nancillae; ancillary.resize(totalQubits); garbage.resize(totalQubits); for (auto i = totalQubits - 1; i > logicalQubitIndex; --i) { @@ -527,7 +502,7 @@ std::ostream& QuantumComputation::print(std::ostream& os) const { size_t i = 0U; for (const auto& op : ops) { os << std::setw(width) << ++i << ":"; - op->print(os, {}, static_cast(width) + 1U); + op->print(os, {}, static_cast(width) + 1U, nqubits); os << "\n"; } @@ -1095,8 +1070,8 @@ void QuantumComputation::measure( << " >= " << cRegister->second.second << ")"; throw QFRException(ss.str()); } - emplace_back( - getNqubits(), qubit, cRegister->second.first + registerBit.second); + emplace_back(qubit, cRegister->second.first + + registerBit.second); } else { std::stringstream ss{}; diff --git a/src/algorithms/GoogleRandomCircuitSampling.cpp b/src/algorithms/GoogleRandomCircuitSampling.cpp index 307161506..bdb6a1394 100644 --- a/src/algorithms/GoogleRandomCircuitSampling.cpp +++ b/src/algorithms/GoogleRandomCircuitSampling.cpp @@ -86,28 +86,27 @@ void GoogleRandomCircuitSampling::importGRCS(const std::string& filename) { ss >> control; ss >> target; cycles[cycle].emplace_back(std::make_unique( - nqubits, Control{static_cast(control)}, - static_cast(target), Z)); + Control{static_cast(control)}, static_cast(target), Z)); } else if (identifier == "is") { ss >> control; ss >> target; cycles[cycle].emplace_back(std::make_unique( - nqubits, qc::Controls{}, static_cast(control), + qc::Controls{}, static_cast(control), static_cast(target), iSWAP)); } else { ss >> target; if (identifier == "h") { - cycles[cycle].emplace_back(std::make_unique( - nqubits, static_cast(target), H)); + cycles[cycle].emplace_back( + std::make_unique(static_cast(target), H)); } else if (identifier == "t") { - cycles[cycle].emplace_back(std::make_unique( - nqubits, static_cast(target), T)); + cycles[cycle].emplace_back( + std::make_unique(static_cast(target), T)); } else if (identifier == "x_1_2") { cycles[cycle].emplace_back(std::make_unique( - nqubits, static_cast(target), RX, std::vector{PI_2})); + static_cast(target), RX, std::vector{PI_2})); } else if (identifier == "y_1_2") { cycles[cycle].emplace_back(std::make_unique( - nqubits, static_cast(target), RY, std::vector{PI_2})); + static_cast(target), RY, std::vector{PI_2})); } else { throw QFRException("Unknown gate '" + identifier); } @@ -131,7 +130,7 @@ std::ostream& GoogleRandomCircuitSampling::print(std::ostream& os) const { for (const auto& op : cycle) { os << std::setw(static_cast(std::log10(getNops()) + 1.)) << ++j << ": "; - op->print(os, initialLayout, 0U); + op->print(os, initialLayout, 0U, nqubits); os << "\n"; } } diff --git a/src/dd/Operations.cpp b/src/dd/Operations.cpp index 7062ecc05..eeaf66782 100644 --- a/src/dd/Operations.cpp +++ b/src/dd/Operations.cpp @@ -7,7 +7,6 @@ void dumpTensor(qc::Operation* op, std::ostream& of, Package& dd) { const auto type = op->getType(); if (op->isStandardOperation()) { - auto nqubits = op->getNqubits(); const auto& controls = op->getControls(); const auto& targets = op->getTargets(); @@ -55,7 +54,6 @@ void dumpTensor(qc::Operation* op, std::ostream& of, // write tensor dimensions const std::size_t localQubits = targets.size() + controls.size(); - const std::size_t globalQubits = nqubits; of << "["; for (std::size_t q = 0U; q < localQubits; ++q) { if (q != 0U) { @@ -78,8 +76,6 @@ void dumpTensor(qc::Operation* op, std::ostream& of, } ++localIdx; } - // temporarily change nqubits - op->setNqubits(localQubits); // get DD for local operation auto localOp = op->clone(); @@ -90,9 +86,6 @@ void dumpTensor(qc::Operation* op, std::ostream& of, // translate local DD to matrix const auto localMatrix = localDD.getMatrix(localQubits); - // restore nqubits - op->setNqubits(globalQubits); - // set appropriate precision for dumping numbers const auto precision = of.precision(); of.precision(std::numeric_limits::max_digits10); diff --git a/src/dd/Simulation.cpp b/src/dd/Simulation.cpp index 41f45dba1..10f9f052b 100644 --- a/src/dd/Simulation.cpp +++ b/src/dd/Simulation.cpp @@ -151,8 +151,8 @@ simulate(const QuantumComputation* qc, const VectorDD& in, Package& dd, e, static_cast(permutation.at(qubit)), true, mt); // apply an X operation whenever the measured result is one if (bit == '1') { - const auto x = qc::StandardOperation( - qc->getNqubits(), permutation.at(qubit), qc::X); + const auto x = + qc::StandardOperation(permutation.at(qubit), qc::X); auto tmp = dd.multiply(getDD(&x, dd), e); dd.incRef(tmp); dd.decRef(e); diff --git a/src/ecc/Q3Shor.cpp b/src/ecc/Q3Shor.cpp index e591a44fa..4dcf02131 100644 --- a/src/ecc/Q3Shor.cpp +++ b/src/ecc/Q3Shor.cpp @@ -68,12 +68,10 @@ void Q3Shor::addOperation(const qc::Controls& controls, const auto numTargets = targets.size(); const auto numControls = controls.size(); const auto numQubits = qcOriginal->getNqubits(); - const auto numMappedQubits = qcMapped->getNqubits(); for (std::size_t j = 0; j < numTargets; j++) { auto i = targets[j]; if (numControls > 0) { - qcMapped->emplace_back(numMappedQubits, controls, - i, type); + qcMapped->emplace_back(controls, i, type); qc::Controls controls2; qc::Controls controls3; for (const auto& ct : controls) { @@ -83,16 +81,15 @@ void Q3Shor::addOperation(const qc::Controls& controls, qc::Control{static_cast(ct.qubit + 2 * numQubits), ct.type}); } qcMapped->emplace_back( - numMappedQubits, controls2, static_cast(i + numQubits), type); + controls2, static_cast(i + numQubits), type); qcMapped->emplace_back( - numMappedQubits, controls3, static_cast(i + 2 * numQubits), - type); + controls3, static_cast(i + 2 * numQubits), type); } else { - qcMapped->emplace_back(numMappedQubits, i, type); + qcMapped->emplace_back(i, type); qcMapped->emplace_back( - numMappedQubits, static_cast(i + numQubits), type); + static_cast(i + numQubits), type); qcMapped->emplace_back( - numMappedQubits, static_cast(i + 2 * numQubits), type); + static_cast(i + 2 * numQubits), type); } } } diff --git a/src/ecc/Q5Laflamme.cpp b/src/ecc/Q5Laflamme.cpp index dce35c468..9b3217ead 100644 --- a/src/ecc/Q5Laflamme.cpp +++ b/src/ecc/Q5Laflamme.cpp @@ -137,8 +137,7 @@ void Q5Laflamme::mapGate(const qc::Operation& gate) { } else { for (Qubit j = 0; j < N_REDUNDANT_QUBITS; j++) { qcMapped->emplace_back( - qcMapped->getNqubits(), static_cast(i + j * nQubits), - gate.getType()); + static_cast(i + j * nQubits), gate.getType()); } } } diff --git a/src/ecc/Q7Steane.cpp b/src/ecc/Q7Steane.cpp index 2a1228859..f1ffb5922 100644 --- a/src/ecc/Q7Steane.cpp +++ b/src/ecc/Q7Steane.cpp @@ -116,7 +116,6 @@ void Q7Steane::addSOperation(const qc::Controls& controls, const auto numTargets = targets.size(); const auto numControls = controls.size(); const auto numQubits = qcOriginal->getNqubits(); - const auto numMappedQubits = qcMapped->getNqubits(); for (std::size_t k = 0; k < numTargets; k++) { auto i = targets[k]; @@ -128,23 +127,20 @@ void Q7Steane::addSOperation(const qc::Controls& controls, ct.type); } qcMapped->emplace_back( - numMappedQubits, controls2, static_cast(i + j * numQubits), - type); + controls2, static_cast(i + j * numQubits), type); qcMapped->emplace_back( - numMappedQubits, controls2, static_cast(i + j * numQubits), - type); + controls2, static_cast(i + j * numQubits), type); qcMapped->emplace_back( - numMappedQubits, controls2, static_cast(i + j * numQubits), - type); + controls2, static_cast(i + j * numQubits), type); } } else { for (std::size_t j = 0; j < N_REDUNDANT_QUBITS; j++) { qcMapped->emplace_back( - numMappedQubits, static_cast(i + j * numQubits), type); + static_cast(i + j * numQubits), type); qcMapped->emplace_back( - numMappedQubits, static_cast(i + j * numQubits), type); + static_cast(i + j * numQubits), type); qcMapped->emplace_back( - numMappedQubits, static_cast(i + j * numQubits), type); + static_cast(i + j * numQubits), type); } } } @@ -173,14 +169,12 @@ void Q7Steane::mapGate(const qc::Operation& gate) { static_cast(ct.qubit + j * nQubits), ct.type}); } qcMapped->emplace_back( - qcMapped->getNqubits(), ctrls2, - static_cast(i + j * nQubits), gate.getType()); + ctrls2, static_cast(i + j * nQubits), gate.getType()); } } else { for (std::size_t j = 0; j < N_REDUNDANT_QUBITS; j++) { qcMapped->emplace_back( - qcMapped->getNqubits(), static_cast(i + j * nQubits), - gate.getType()); + static_cast(i + j * nQubits), gate.getType()); } } } diff --git a/src/ecc/Q9Shor.cpp b/src/ecc/Q9Shor.cpp index 301980f0e..446149b17 100644 --- a/src/ecc/Q9Shor.cpp +++ b/src/ecc/Q9Shor.cpp @@ -185,8 +185,7 @@ void Q9Shor::mapGate(const qc::Operation& gate) { qcMapped->h(static_cast(ct.qubit + j * nQubits)); } qcMapped->emplace_back( - qcMapped->getNqubits(), controls2, - static_cast(i + j * nQubits), type); + controls2, static_cast(i + j * nQubits), type); for (const auto& ct : controls) { qcMapped->h(static_cast(ct.qubit + j * nQubits)); } @@ -194,7 +193,7 @@ void Q9Shor::mapGate(const qc::Operation& gate) { } else { for (size_t j = 0; j < N_REDUNDANT_QUBITS; j++) { qcMapped->emplace_back( - qcMapped->getNqubits(), static_cast(i + j * nQubits), type); + static_cast(i + j * nQubits), type); } } } diff --git a/src/mqt/core/_core/operations.pyi b/src/mqt/core/_core/operations.pyi index 8f5d4fec9..00ef36fd1 100644 --- a/src/mqt/core/_core/operations.pyi +++ b/src/mqt/core/_core/operations.pyi @@ -93,7 +93,6 @@ class OpType: class Operation(ABC): type_: OpType controls: set[Control] - num_qubits: int targets: list[int] parameter: list[float] @property @@ -136,73 +135,57 @@ class StandardOperation(Operation): @overload def __init__( self: Self, - nq: int, target: int, op_type: OpType, params: Sequence[float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, targets: Sequence[int], op_type: OpType, params: Sequence[float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, control: Control, target: int, op_type: OpType, params: Sequence[float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, control: Control, targets: Sequence[int], op_type: OpType, params: Sequence[float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, controls: set[Control], target: int, op_type: OpType, params: Sequence[float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, controls: set[Control], targets: Sequence[int], op_type: OpType, params: Sequence[float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload - def __init__(self: Self, nq: int, controls: set[Control], target: int, starting_qubit: int = 0) -> None: ... - @overload def __init__( self: Self, - nq: int, controls: set[Control], target0: int, target1: int, op_type: OpType, params: Sequence[float] | None = None, - starting_qubit: int = 0, ) -> None: ... def add_control(self: Self, control: Control) -> None: ... def clear_controls(self: Self) -> None: ... @@ -215,11 +198,11 @@ class NonUnitaryOperation(Operation): @property def classics(self: Self) -> list[int]: ... @overload - def __init__(self: Self, nq: int, targets: Sequence[int], classics: Sequence[int]) -> None: ... + def __init__(self: Self, targets: Sequence[int], classics: Sequence[int]) -> None: ... @overload - def __init__(self: Self, nq: int, target: int, classic: int) -> None: ... + def __init__(self: Self, target: int, classic: int) -> None: ... @overload - def __init__(self: Self, nq: int, targets: Sequence[int], op_type: OpType = ...) -> None: ... + def __init__(self: Self, targets: Sequence[int], op_type: OpType = ...) -> None: ... def add_control(self: Self, control: Control) -> None: ... def clear_controls(self: Self) -> None: ... def remove_control(self: Self, control: Control) -> None: ... @@ -229,9 +212,9 @@ class NonUnitaryOperation(Operation): class CompoundOperation(Operation): @overload - def __init__(self: Self, nq: int) -> None: ... + def __init__(self: Self) -> None: ... @overload - def __init__(self: Self, nq: int, ops: Sequence[Operation]) -> None: ... + def __init__(self: Self, ops: Sequence[Operation]) -> None: ... def __len__(self: Self) -> int: ... @overload def __getitem__(self: Self, idx: int) -> Operation: ... @@ -252,71 +235,57 @@ class SymbolicOperation(StandardOperation): @overload def __init__( self: Self, - nq: int, target: int, op_type: OpType, params: Sequence[Expression | float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, targets: Sequence[int], op_type: OpType, params: Sequence[Expression | float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, control: Control, target: int, op_type: OpType, params: Sequence[Expression | float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, control: Control, targets: Sequence[int], op_type: OpType, params: Sequence[Expression | float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, controls: set[Control], target: int, op_type: OpType, params: Sequence[Expression | float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, controls: set[Control], targets: Sequence[int], op_type: OpType, params: Sequence[Expression | float] | None = None, - starting_qubit: int = 0, ) -> None: ... @overload def __init__( self: Self, - nq: int, controls: set[Control], target0: int, target1: int, op_type: OpType, params: Sequence[Expression | float] | None = None, - starting_qubit: int = 0, ) -> None: ... def get_parameter(self: Self, idx: int) -> Expression | float: ... def get_parameters(self: Self) -> list[Expression | float]: ... diff --git a/src/mqt/core/io.py b/src/mqt/core/io.py index 6ae49a8e1..184473bbd 100644 --- a/src/mqt/core/io.py +++ b/src/mqt/core/io.py @@ -16,9 +16,7 @@ def load(input_circuit: QuantumComputation | str | PathLike[str] | QuantumCircui """Load a quantum circuit from any supported format as a ``QuantumComputation``. Args: - input_circuit: The input circuit to translate to a ``QuantumComputation``. - This can be a `QuantumComputation` itself, a file name to any of the supported file formats, - an OpenQASM (2.0 or 3.0) string, or a Qiskit `QuantumCircuit`. + input_circuit: The input circuit to translate to a ``QuantumComputation``. This can be a `QuantumComputation` itself, a file name to any of the supported file formats, an OpenQASM (2.0 or 3.0) string, or a Qiskit `QuantumCircuit`. Returns: The ``QuantumComputation``. diff --git a/src/mqt/core/plugins/qiskit.py b/src/mqt/core/plugins/qiskit.py index a3adea2b1..2096399e3 100644 --- a/src/mqt/core/plugins/qiskit.py +++ b/src/mqt/core/plugins/qiskit.py @@ -164,15 +164,15 @@ def _emplace_operation( if name == "measure": clbits = [clbit_map[clbit] for clbit in cargs] - qc.append(NonUnitaryOperation(qc.num_qubits, qubits, clbits)) + qc.append(NonUnitaryOperation(qubits, clbits)) return [] if name == "reset": - qc.append(NonUnitaryOperation(qc.num_qubits, qubits)) + qc.append(NonUnitaryOperation(qubits)) return [] if name == "barrier": - qc.append(StandardOperation(qc.num_qubits, qubits, OpType.barrier)) + qc.append(StandardOperation(qubits, OpType.barrier)) return [] if name in {"i", "id", "iden"}: @@ -333,9 +333,9 @@ def _add_operation( controls = {Control(qubit) for qubit in qubits} parameters = [_parse_symbolic_expression(param) for param in params] if any(isinstance(parameter, Expression) for parameter in parameters): - qc.append(SymbolicOperation(qc.num_qubits, controls, target, type_, parameters)) + qc.append(SymbolicOperation(controls, target, type_, parameters)) else: - qc.append(StandardOperation(qc.num_qubits, controls, target, type_, cast(List[float], parameters))) + qc.append(StandardOperation(controls, target, type_, cast(List[float], parameters))) return parameters @@ -352,9 +352,9 @@ def _add_two_target_operation( controls = {Control(qubit) for qubit in qubits} parameters = [_parse_symbolic_expression(param) for param in params] if any(isinstance(parameter, Expression) for parameter in parameters): - qc.append(SymbolicOperation(qc.num_qubits, controls, target1, target2, type_, parameters)) + qc.append(SymbolicOperation(controls, target1, target2, type_, parameters)) else: - qc.append(StandardOperation(qc.num_qubits, controls, target1, target2, type_, cast(List[float], parameters))) + qc.append(StandardOperation(controls, target1, target2, type_, cast(List[float], parameters))) return parameters @@ -407,7 +407,7 @@ def _import_definition( qarg_map = dict(zip(circ.qubits, qargs)) carg_map = dict(zip(circ.clbits, cargs)) - qc.append(CompoundOperation(qc.num_qubits)) + qc.append(CompoundOperation()) comp_op = cast(CompoundOperation, qc[-1]) params = [] diff --git a/src/operations/CompoundOperation.cpp b/src/operations/CompoundOperation.cpp index e313624c2..204e50acb 100644 --- a/src/operations/CompoundOperation.cpp +++ b/src/operations/CompoundOperation.cpp @@ -3,15 +3,14 @@ #include namespace qc { -CompoundOperation::CompoundOperation(const std::size_t nq) { +CompoundOperation::CompoundOperation() { name = "Compound operation:"; - nqubits = nq; type = Compound; } CompoundOperation::CompoundOperation( - const std::size_t nq, std::vector>&& operations) - : CompoundOperation(nq) { + std::vector>&& operations) + : CompoundOperation() { // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) ops = std::move(operations); } @@ -38,13 +37,6 @@ std::unique_ptr CompoundOperation::clone() const { return std::make_unique(*this); } -void CompoundOperation::setNqubits(const std::size_t nq) { - nqubits = nq; - for (auto& op : ops) { - op->setNqubits(nq); - } -} - bool CompoundOperation::isNonUnitaryOperation() const { return std::any_of(ops.cbegin(), ops.cend(), [](const auto& op) { return op->isNonUnitaryOperation(); @@ -118,12 +110,13 @@ bool CompoundOperation::equals(const Operation& operation) const { std::ostream& CompoundOperation::print(std::ostream& os, const Permutation& permutation, - const std::size_t prefixWidth) const { + const std::size_t prefixWidth, + const std::size_t nqubits) const { const auto prefix = std::string(prefixWidth - 1, ' '); os << std::string(4 * nqubits, '-') << "\n"; for (const auto& op : ops) { os << prefix << ":"; - op->print(os, permutation, prefixWidth); + op->print(os, permutation, prefixWidth, nqubits); os << "\n"; } os << prefix << std::string(4 * nqubits + 1, '-'); diff --git a/src/operations/NonUnitaryOperation.cpp b/src/operations/NonUnitaryOperation.cpp index eda5caea2..43231784d 100644 --- a/src/operations/NonUnitaryOperation.cpp +++ b/src/operations/NonUnitaryOperation.cpp @@ -12,12 +12,10 @@ namespace qc { // Measurement constructor -NonUnitaryOperation::NonUnitaryOperation(const std::size_t nq, - std::vector qubitRegister, +NonUnitaryOperation::NonUnitaryOperation(std::vector qubitRegister, std::vector classicalRegister) : classics(std::move(classicalRegister)) { type = Measure; - nqubits = nq; targets = std::move(qubitRegister); name = toString(type); if (targets.size() != classics.size()) { @@ -25,34 +23,31 @@ NonUnitaryOperation::NonUnitaryOperation(const std::size_t nq, "Sizes of qubit register and classical register do not match."); } } -NonUnitaryOperation::NonUnitaryOperation(const std::size_t nq, - const Qubit qubit, const Bit cbit) +NonUnitaryOperation::NonUnitaryOperation(const Qubit qubit, const Bit cbit) : classics({cbit}) { type = Measure; - nqubits = nq; targets = {qubit}; name = toString(type); } // General constructor -NonUnitaryOperation::NonUnitaryOperation(const std::size_t nq, Targets qubits, - OpType op) { +NonUnitaryOperation::NonUnitaryOperation(Targets qubits, OpType op) { type = op; - nqubits = nq; targets = std::move(qubits); std::sort(targets.begin(), targets.end()); name = toString(type); } -std::ostream& NonUnitaryOperation::print( - std::ostream& os, const Permutation& permutation, - [[maybe_unused]] const std::size_t prefixWidth) const { +std::ostream& +NonUnitaryOperation::print(std::ostream& os, const Permutation& permutation, + [[maybe_unused]] const std::size_t prefixWidth, + const std::size_t nqubits) const { switch (type) { case Measure: - printMeasurement(os, targets, classics, permutation); + printMeasurement(os, targets, classics, permutation, nqubits); break; case Reset: - printReset(os, targets, permutation); + printReset(os, targets, permutation, nqubits); break; default: break; @@ -146,9 +141,11 @@ bool NonUnitaryOperation::equals(const Operation& op, const Permutation& perm1, return false; } -void NonUnitaryOperation::printMeasurement( - std::ostream& os, const std::vector& q, const std::vector& c, - const Permutation& permutation) const { +void NonUnitaryOperation::printMeasurement(std::ostream& os, + const std::vector& q, + const std::vector& c, + const Permutation& permutation, + const std::size_t nqubits) { auto qubitIt = q.cbegin(); auto classicIt = c.cbegin(); if (permutation.empty()) { @@ -176,7 +173,8 @@ void NonUnitaryOperation::printMeasurement( void NonUnitaryOperation::printReset(std::ostream& os, const std::vector& q, - const Permutation& permutation) const { + const Permutation& permutation, + const std::size_t nqubits) const { const auto actualTargets = permutation.apply(q); for (std::size_t i = 0; i < nqubits; ++i) { if (std::find(actualTargets.cbegin(), actualTargets.cend(), i) != diff --git a/src/operations/Operation.cpp b/src/operations/Operation.cpp index 45b9462a9..d6df82eef 100644 --- a/src/operations/Operation.cpp +++ b/src/operations/Operation.cpp @@ -41,9 +41,9 @@ std::ostream& Operation::printParameters(std::ostream& os) const { return os; } -std::ostream& -Operation::print(std::ostream& os, const Permutation& permutation, - [[maybe_unused]] const std::size_t prefixWidth) const { +std::ostream& Operation::print(std::ostream& os, const Permutation& permutation, + [[maybe_unused]] const std::size_t prefixWidth, + const std::size_t nqubits) const { const auto precBefore = std::cout.precision(20); const auto& actualControls = permutation.apply(getControls()); const auto& actualTargets = permutation.apply(getTargets()); diff --git a/src/operations/StandardOperation.cpp b/src/operations/StandardOperation.cpp index 59247ffd0..f176bab81 100644 --- a/src/operations/StandardOperation.cpp +++ b/src/operations/StandardOperation.cpp @@ -161,9 +161,7 @@ void StandardOperation::checkUgate() { } } -void StandardOperation::setup(const std::size_t nq, const Qubit startingQubit) { - nqubits = nq; - startQubit = startingQubit; +void StandardOperation::setup() { checkUgate(); name = toString(type); } @@ -171,71 +169,55 @@ void StandardOperation::setup(const std::size_t nq, const Qubit startingQubit) { /*** * Constructors ***/ -StandardOperation::StandardOperation(const std::size_t nq, const Qubit target, - const OpType g, std::vector params, - const Qubit startingQubit) { +StandardOperation::StandardOperation(const Qubit target, const OpType g, + std::vector params) { type = g; parameter = std::move(params); - setup(nq, startingQubit); + setup(); targets.emplace_back(target); } -StandardOperation::StandardOperation(const std::size_t nq, const Targets& targ, - const OpType g, std::vector params, - const Qubit startingQubit) { +StandardOperation::StandardOperation(const Targets& targ, const OpType g, + std::vector params) { type = g; parameter = std::move(params); - setup(nq, startingQubit); + setup(); targets = targ; } -StandardOperation::StandardOperation(const std::size_t nq, - const Control control, const Qubit target, +StandardOperation::StandardOperation(const Control control, const Qubit target, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : StandardOperation(nq, target, g, params, startingQubit) { + const std::vector& params) + : StandardOperation(target, g, params) { controls.insert(control); } -StandardOperation::StandardOperation(const std::size_t nq, - const Control control, const Targets& targ, +StandardOperation::StandardOperation(const Control control, const Targets& targ, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : StandardOperation(nq, targ, g, params, startingQubit) { + const std::vector& params) + : StandardOperation(targ, g, params) { controls.insert(control); } -StandardOperation::StandardOperation(const std::size_t nq, const Controls& c, - const Qubit target, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : StandardOperation(nq, target, g, params, startingQubit) { +StandardOperation::StandardOperation(const Controls& c, const Qubit target, + const OpType g, + const std::vector& params) + : StandardOperation(target, g, params) { controls = c; } -StandardOperation::StandardOperation(const std::size_t nq, const Controls& c, - const Targets& targ, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : StandardOperation(nq, targ, g, params, startingQubit) { +StandardOperation::StandardOperation(const Controls& c, const Targets& targ, + const OpType g, + const std::vector& params) + : StandardOperation(targ, g, params) { controls = c; } -// MCT Constructor -StandardOperation::StandardOperation(const std::size_t nq, const Controls& c, - const Qubit target, - const Qubit startingQubit) - : StandardOperation(nq, c, target, X, {}, startingQubit) {} - // MCF (cSWAP), Peres, parameterized two target Constructor -StandardOperation::StandardOperation(const std::size_t nq, const Controls& c, - const Qubit target0, const Qubit target1, - const OpType g, - const std::vector& params, - const Qubit startingQubit) - : StandardOperation(nq, c, {target0, target1}, g, params, startingQubit) {} +StandardOperation::StandardOperation(const Controls& c, const Qubit target0, + const Qubit target1, const OpType g, + const std::vector& params) + : StandardOperation(c, {target0, target1}, g, params) {} /*** * Public Methods diff --git a/src/operations/SymbolicOperation.cpp b/src/operations/SymbolicOperation.cpp index ea1f31023..6fb0b6089 100644 --- a/src/operations/SymbolicOperation.cpp +++ b/src/operations/SymbolicOperation.cpp @@ -190,17 +190,13 @@ void SymbolicOperation::checkSymbolicUgate() { // NOLINTEND(bugprone-unchecked-optional-access) } -void SymbolicOperation::setup(const std::size_t nq, - const std::vector& params, - const Qubit startingQubit) { - nqubits = nq; +void SymbolicOperation::setup(const std::vector& params) { const auto numParams = params.size(); parameter.resize(numParams); symbolicParameter.resize(numParams); for (std::size_t i = 0; i < numParams; ++i) { storeSymbolOrNumber(params[i], i); } - startQubit = startingQubit; checkSymbolicUgate(); name = toString(type); } @@ -214,65 +210,55 @@ SymbolicOperation::getInstantiation(const SymbolOrNumber& symOrNum, symOrNum); } -SymbolicOperation::SymbolicOperation(const std::size_t nq, const Qubit target, - const OpType g, - const std::vector& params, - const Qubit startingQubit) { +SymbolicOperation::SymbolicOperation( + const Qubit target, const OpType g, + const std::vector& params) { type = g; - setup(nq, params, startingQubit); + setup(params); targets.emplace_back(target); } -SymbolicOperation::SymbolicOperation(const std::size_t nq, const Targets& targ, - const OpType g, - const std::vector& params, - const Qubit startingQubit) { +SymbolicOperation::SymbolicOperation( + const Targets& targ, const OpType g, + const std::vector& params) { type = g; - setup(nq, params, startingQubit); + setup(params); targets = targ; } -SymbolicOperation::SymbolicOperation(const std::size_t nq, - const Control control, const Qubit target, +SymbolicOperation::SymbolicOperation(const Control control, const Qubit target, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : SymbolicOperation(nq, target, g, params, startingQubit) { + const std::vector& params) + : SymbolicOperation(target, g, params) { controls.insert(control); } -SymbolicOperation::SymbolicOperation(const std::size_t nq, - const Control control, const Targets& targ, +SymbolicOperation::SymbolicOperation(const Control control, const Targets& targ, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : SymbolicOperation(nq, targ, g, params, startingQubit) { + const std::vector& params) + : SymbolicOperation(targ, g, params) { controls.insert(control); } -SymbolicOperation::SymbolicOperation(const std::size_t nq, const Controls& c, - const Qubit target, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : SymbolicOperation(nq, target, g, params, startingQubit) { +SymbolicOperation::SymbolicOperation(const Controls& c, const Qubit target, + const OpType g, + const std::vector& params) + : SymbolicOperation(target, g, params) { controls = c; } -SymbolicOperation::SymbolicOperation(const std::size_t nq, const Controls& c, - const Targets& targ, const OpType g, - const std::vector& params, - const Qubit startingQubit) - : SymbolicOperation(nq, targ, g, params, startingQubit) { +SymbolicOperation::SymbolicOperation(const Controls& c, const Targets& targ, + const OpType g, + const std::vector& params) + : SymbolicOperation(targ, g, params) { controls = c; } // MCF (cSWAP), Peres, parameterized two target Constructor -SymbolicOperation::SymbolicOperation(const std::size_t nq, const Controls& c, - const Qubit target0, const Qubit target1, - const OpType g, - const std::vector& params, - const Qubit startingQubit) - : SymbolicOperation(nq, c, {target0, target1}, g, params, startingQubit) {} +SymbolicOperation::SymbolicOperation(const Controls& c, const Qubit target0, + const Qubit target1, const OpType g, + const std::vector& params) + : SymbolicOperation(c, {target0, target1}, g, params) {} bool SymbolicOperation::equals(const Operation& op, const Permutation& perm1, const Permutation& perm2) const { @@ -326,7 +312,7 @@ StandardOperation SymbolicOperation::getInstantiatedOperation( for (std::size_t i = 0; i < size; ++i) { parameters.emplace_back(getInstantiation(getParameter(i), assignment)); } - return {nqubits, targets, type, parameters, startQubit}; + return {controls, targets, type, parameters}; } // Instantiates this Operation diff --git a/src/parsers/QASM3Parser.cpp b/src/parsers/QASM3Parser.cpp index b446c32cd..d0db9bd39 100644 --- a/src/parsers/QASM3Parser.cpp +++ b/src/parsers/QASM3Parser.cpp @@ -141,7 +141,7 @@ class OpenQasm3Parser final : public InstVisitor { public: explicit OpenQasm3Parser(qc::QuantumComputation* quantumComputation) : typeCheckPass(&constEvalPass), qc(quantumComputation) { - for (auto [identifier, builtin] : initializeBuiltins()) { + for (const auto& [identifier, builtin] : initializeBuiltins()) { constEvalPass.addConst(identifier, builtin.first); typeCheckPass.addBuiltin(identifier, builtin.second); } @@ -530,7 +530,7 @@ class OpenQasm3Parser final : public InstVisitor { } // if we are broadcasting, we need to create a compound operation - auto op = std::make_unique(qc->getNqubits()); + auto op = std::make_unique(); for (size_t j = 0; j < broadcastingWidth; ++j) { // first we apply the operation auto nestedOp = applyQuantumOperation( @@ -602,7 +602,7 @@ class OpenQasm3Parser final : public InstVisitor { const std::shared_ptr& debugInfo) { if (auto* standardGate = dynamic_cast(gate.get())) { auto op = std::make_unique( - qc->getNqubits(), qc::Controls{}, targetBits, standardGate->info.type, + qc::Controls{}, targetBits, standardGate->info.type, evaluatedParameters); if (invertOperation) { op->invert(); @@ -627,7 +627,7 @@ class OpenQasm3Parser final : public InstVisitor { index++; } - auto op = std::make_unique(qc->getNqubits()); + auto op = std::make_unique(); for (const auto& nestedGate : compoundGate->body) { if (auto barrierStatement = std::dynamic_pointer_cast(nestedGate); @@ -712,8 +712,7 @@ class OpenQasm3Parser final : public InstVisitor { debugInfo); } - auto op = std::make_unique(qc->getNqubits(), - qubits, bits); + auto op = std::make_unique(qubits, bits); qc->emplace_back(std::move(op)); } @@ -778,7 +777,7 @@ class OpenQasm3Parser final : public InstVisitor { [[nodiscard]] std::unique_ptr translateBlockOperations( const std::vector>& statements) { - auto blockOps = std::make_unique(qc->getNqubits()); + auto blockOps = std::make_unique(); for (const auto& statement : statements) { auto gateCall = std::dynamic_pointer_cast(statement); if (gateCall == nullptr) { @@ -797,26 +796,24 @@ class OpenQasm3Parser final : public InstVisitor { return blockOps; } - [[nodiscard]] std::unique_ptr + [[nodiscard]] static std::unique_ptr getBarrierOp(const std::shared_ptr& barrierStatement, - const qc::QuantumRegisterMap& qregs) const { + const qc::QuantumRegisterMap& qregs) { std::vector qubits{}; for (const auto& gate : barrierStatement->gates) { translateGateOperand(gate, qubits, qregs, barrierStatement->debugInfo); } - return std::make_unique(qc->getNqubits(), qubits, - qc::Barrier); + return std::make_unique(qubits, qc::Barrier); } - [[nodiscard]] std::unique_ptr + [[nodiscard]] static std::unique_ptr getResetOp(const std::shared_ptr& resetStatement, - const qc::QuantumRegisterMap& qregs) const { + const qc::QuantumRegisterMap& qregs) { std::vector qubits{}; translateGateOperand(resetStatement->gate, qubits, qregs, resetStatement->debugInfo); - return std::make_unique(qc->getNqubits(), qubits, - qc::Reset); + return std::make_unique(qubits, qc::Reset); } std::pair diff --git a/src/parsers/QCParser.cpp b/src/parsers/QCParser.cpp index a5cdc27fd..4febaedde 100644 --- a/src/parsers/QCParser.cpp +++ b/src/parsers/QCParser.cpp @@ -293,7 +293,7 @@ void qc::QuantumComputation::readQCGateDescriptions( const Qubit target = controls.back().qubit; controls.pop_back(); emplace_back( - nqubits, Controls{controls.cbegin(), controls.cend()}, target, gate); + Controls{controls.cbegin(), controls.cend()}, target, gate); } else if (gate == SWAP) { const Qubit target0 = controls.back().qubit; controls.pop_back(); @@ -304,7 +304,7 @@ void qc::QuantumComputation::readQCGateDescriptions( const Qubit target = controls.back().qubit; controls.pop_back(); emplace_back( - nqubits, Controls{controls.cbegin(), controls.cend()}, target, gate, + Controls{controls.cbegin(), controls.cend()}, target, gate, std::vector{lambda}); } } diff --git a/src/parsers/RealParser.cpp b/src/parsers/RealParser.cpp index 3d70437e8..4bddfb1fb 100644 --- a/src/parsers/RealParser.cpp +++ b/src/parsers/RealParser.cpp @@ -228,7 +228,7 @@ void qc::QuantumComputation::readRealGateDescriptions(std::istream& is, case V: case Vdg: emplace_back( - nqubits, Controls{controls.cbegin(), controls.cend()}, target, gate); + Controls{controls.cbegin(), controls.cend()}, target, gate); break; case X: mcx(Controls{controls.cbegin(), controls.cend()}, target); @@ -238,7 +238,7 @@ void qc::QuantumComputation::readRealGateDescriptions(std::istream& is, case RZ: case P: emplace_back( - nqubits, Controls{controls.cbegin(), controls.cend()}, target, gate, + Controls{controls.cbegin(), controls.cend()}, target, gate, std::vector{PI / (lambda)}); break; case SWAP: @@ -248,8 +248,7 @@ void qc::QuantumComputation::readRealGateDescriptions(std::istream& is, const auto target1 = controls.back().qubit; controls.pop_back(); emplace_back( - nqubits, Controls{controls.cbegin(), controls.cend()}, target1, - target, gate); + Controls{controls.cbegin(), controls.cend()}, target1, target, gate); break; } default: diff --git a/src/python/operations/register_compound_operation.cpp b/src/python/operations/register_compound_operation.cpp index 27e2adbeb..21dca7760 100644 --- a/src/python/operations/register_compound_operation.cpp +++ b/src/python/operations/register_compound_operation.cpp @@ -20,18 +20,16 @@ void registerCompoundOperation(py::module& m) { py::class_( m, "CompoundOperation", "Quantum operation comprised of multiple sub-operations.") - .def(py::init(), "nq"_a, - "Create an empty compound operation on `nq` qubits.") - .def(py::init([](std::size_t nq, std::vector& ops) { + .def(py::init<>(), "Create an empty compound operation.") + .def(py::init([](std::vector& ops) { std::vector> uniqueOps; uniqueOps.reserve(ops.size()); for (auto& op : ops) { uniqueOps.emplace_back(op->clone()); } - return qc::CompoundOperation(nq, std::move(uniqueOps)); + return qc::CompoundOperation(std::move(uniqueOps)); }), - "nq"_a, "ops"_a, - "Create a compound operation from a list of operations.") + "ops"_a, "Create a compound operation from a list of operations.") .def("__len__", &qc::CompoundOperation::size, "Return number of sub-operations.") .def( @@ -72,7 +70,7 @@ void registerCompoundOperation(py::module& m) { .def("empty", &qc::CompoundOperation::empty) .def("__repr__", [](const qc::CompoundOperation& op) { std::stringstream ss; - ss << "CompoundOperation(" << op.getNqubits() << ", [...ops...])"; + ss << "CompoundOperation([..." << op.size() << " ops...])"; return ss.str(); }); } diff --git a/src/python/operations/register_non_unitary_operation.cpp b/src/python/operations/register_non_unitary_operation.cpp index 66b1e001a..b25391a98 100644 --- a/src/python/operations/register_non_unitary_operation.cpp +++ b/src/python/operations/register_non_unitary_operation.cpp @@ -7,16 +7,14 @@ void registerNonUnitaryOperation(py::module& m) { py::class_( m, "NonUnitaryOperation", "Non-unitary operations such as measurements and resets.") - .def( - py::init, std::vector>(), - "nq"_a, "targets"_a, "classics"_a, - "Create a multi-qubit measurement operation.") - .def(py::init(), "nq"_a, "target"_a, - "classic"_a, + .def(py::init, std::vector>(), + "targets"_a, "classics"_a, + "Create a multi-qubit measurement operation.") + .def(py::init(), "target"_a, "classic"_a, "Create a measurement operation that measures `target` into " "`classic`.") - .def(py::init, qc::OpType>(), "nq"_a, - "targets"_a, "op_type"_a = qc::OpType::Reset, + .def(py::init, qc::OpType>(), "targets"_a, + "op_type"_a = qc::OpType::Reset, "Create a multi-qubit reset operation.") .def_property_readonly( "classics", @@ -25,7 +23,7 @@ void registerNonUnitaryOperation(py::module& m) { "Return the classical bits.") .def("__repr__", [](const qc::NonUnitaryOperation& op) { std::stringstream ss; - ss << "NonUnitaryOperation(" << op.getNqubits() << ", "; + ss << "NonUnitaryOperation("; const auto& targets = op.getTargets(); if (targets.size() == 1U) { ss << "target=" << targets[0]; diff --git a/src/python/operations/register_operation.cpp b/src/python/operations/register_operation.cpp index ed38a1ffe..3d275c761 100644 --- a/src/python/operations/register_operation.cpp +++ b/src/python/operations/register_operation.cpp @@ -28,8 +28,6 @@ void registerOperation(py::module& m) { "control"_a, "Remove a control from this operation.") .def("remove_controls", &qc::Operation::removeControls, "controls"_a, "Remove a list of controls from this operation.") - .def_property("num_qubits", &qc::Operation::getNqubits, - &qc::Operation::setNqubits) .def("get_used_qubits", &qc::Operation::getUsedQubits, "Get the qubits used by the operation (both control and targets).") .def("acts_on", &qc::Operation::actsOn, "qubit"_a, @@ -77,15 +75,9 @@ void registerOperation(py::module& m) { [](const qc::Operation& op) { return std::hash{}(op); }) - .def("__str__", - [](const qc::Operation& op) { - std::ostringstream oss; - oss << op; - return oss.str(); - }) .def("__repr__", [](const qc::Operation& op) { std::ostringstream oss; - oss << op; + oss << "Operation(type=" << op.getType() << ", ...)"; return oss.str(); }); } diff --git a/src/python/operations/register_standard_operation.cpp b/src/python/operations/register_standard_operation.cpp index 045193aa6..ee74a13e1 100644 --- a/src/python/operations/register_standard_operation.cpp +++ b/src/python/operations/register_standard_operation.cpp @@ -13,49 +13,42 @@ void registerStandardOperation(py::module& m) { "CNOT, SWAP, etc. as well primitives like barriers.") .def(py::init<>(), "Create an empty standard operation. This is " "equivalent to the identity gate.") - .def(py::init, - qc::Qubit>(), - "nq"_a, "target"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, + .def(py::init>(), "target"_a, + "op_type"_a, "params"_a = std::vector{}, "Create a single-qubit standard operation of specified type.") - .def(py::init, qc::Qubit>(), - "nq"_a, "targets"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, + .def(py::init>(), + "targets"_a, "op_type"_a, "params"_a = std::vector{}, "Create a multi-qubit standard operation of specified type.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "control"_a, "target"_a, "op_type"_a, - "params"_a = std::vector{}, "starting_qubit"_a = 0, + .def(py::init&>(), + "control"_a, "target"_a, "op_type"_a, + "params"_a = std::vector{}, "Create a controlled standard operation of specified type.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "control"_a, "targets"_a, "op_type"_a, - "params"_a = std::vector{}, "starting_qubit"_a = 0, + .def(py::init&>(), + "control"_a, "targets"_a, "op_type"_a, + "params"_a = std::vector{}, "Create a controlled multi-target standard operation of specified " "type.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "controls"_a, "target"_a, "op_type"_a, - "params"_a = std::vector{}, "starting_qubit"_a = 0, + .def(py::init&>(), + "controls"_a, "target"_a, "op_type"_a, + "params"_a = std::vector{}, "Create a multi-controlled standard operation of specified type.") - .def(py::init, qc::Qubit>(), - "nq"_a, "controls"_a, "targets"_a, "op_type"_a, - "params"_a = std::vector{}, "starting_qubit"_a = 0, + .def(py::init>(), + "controls"_a, "targets"_a, "op_type"_a, + "params"_a = std::vector{}, "Create a multi-controlled multi-target standard operation of " "specified type.") - .def(py::init(), - "nq"_a, "controls"_a, "target"_a, "starting_qubit"_a = 0, - "Create a multi-controlled X operation.") - .def(py::init, qc::Qubit>(), - "nq"_a, "controls"_a, "target0"_a, "target1"_a, "op_type"_a, - "params"_a = std::vector{}, "starting_qubit"_a = 0, + .def(py::init>(), + "controls"_a, "target0"_a, "target1"_a, "op_type"_a, + "params"_a = std::vector{}, "Create a multi-controlled two-target operation of specified type.") .def("__repr__", [](const qc::StandardOperation& op) { std::stringstream ss; - ss << "StandardOperation(" << op.getNqubits() << ", "; + ss << "StandardOperation("; const auto& controls = op.getControls(); if (controls.size() == 1U) { ss << "control="; diff --git a/src/python/operations/register_symbolic_operation.cpp b/src/python/operations/register_symbolic_operation.cpp index b4fbecc11..783b70349 100644 --- a/src/python/operations/register_symbolic_operation.cpp +++ b/src/python/operations/register_symbolic_operation.cpp @@ -10,61 +10,52 @@ void registerSymbolicOperation(py::module& m) { "This encompasses all symbolic versions of `StandardOperation` that " "involve (float) angle parameters.") .def(py::init<>(), "Create an empty symbolic operation.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "target"_a, "op_type"_a, + .def(py::init&>(), + "target"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, "Create a symbolic operation acting on a single qubit." "Params is a list of parameters that can be either `Expression` or " "`float`.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "targets"_a, "op_type"_a, + .def(py::init&>(), + "targets"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, "Create a symbolic operation acting on multiple qubits." "Params is a list of parameters that can be either `Expression` or " "`float`.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "control"_a, "target"_a, "op_type"_a, + .def(py::init&>(), + "control"_a, "target"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, "Create a controlled symbolic operation." "Params is a list of parameters that can be either `Expression` or " "`float`.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "control"_a, "targets"_a, "op_type"_a, + .def(py::init&>(), + "control"_a, "targets"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, "Create a controlled multi-target symbolic operation." "Params is a list of parameters that can be either `Expression` or " "`float`.") - .def(py::init&, qc::Qubit>(), - "nq"_a, "controls"_a, "target"_a, "op_type"_a, + .def(py::init&>(), + "controls"_a, "target"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, "Create a multi-controlled symbolic operation." "Params is a list of parameters that can be either `Expression` or " "`float`.") - .def(py::init&, - qc::Qubit>(), - "nq"_a, "controls"_a, "targets"_a, "op_type"_a, + .def(py::init&>(), + "controls"_a, "targets"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, "Create a multi-controlled multi-target symbolic operation." "Params is a list of parameters that can be either `Expression` or " "`float`.") - .def(py::init&, - qc::Qubit>(), - "nq"_a, "controls"_a, "target0"_a, "target1"_a, "op_type"_a, + .def(py::init&>(), + "controls"_a, "target0"_a, "target1"_a, "op_type"_a, "params"_a = std::vector{}, - "starting_qubit"_a = 0, "Create a multi-controlled two-target symbolic operation." "Params is a list of parameters that can be either `Expression` or " "`float`.") diff --git a/src/python/qiskit/QuantumCircuit.cpp b/src/python/qiskit/QuantumCircuit.cpp index 54fba1b2a..531de857e 100644 --- a/src/python/qiskit/QuantumCircuit.cpp +++ b/src/python/qiskit/QuantumCircuit.cpp @@ -119,14 +119,14 @@ void qc::qiskit::QuantumCircuit::emplaceOperation( if (instructionName == "measure") { auto control = qubitMap[qargs[0]].cast(); auto target = clbitMap[cargs[0]].cast(); - qc.emplace_back(qc.getNqubits(), control, target); + qc.emplace_back(control, target); } else if (instructionName == "barrier") { Targets targets{}; for (const auto qubit : qargs) { auto target = qubitMap[qubit].cast(); targets.emplace_back(target); } - qc.emplace_back(qc.getNqubits(), targets, Barrier); + qc.emplace_back(targets, Barrier); } else if (instructionName == "reset") { Targets targets{}; for (const auto qubit : qargs) { @@ -223,8 +223,8 @@ void qc::qiskit::QuantumCircuit::emplaceOperation( qubitMap, clbitMap); } catch (py::error_already_set& e) { std::cerr << "Failed to import instruction " << instructionName - << " from Qiskit QuantumCircuit" << std::endl; - std::cerr << e.what() << std::endl; + << " from Qiskit QuantumCircuit\n"; + std::cerr << e.what() << "\n"; } } } @@ -311,7 +311,7 @@ void qc::qiskit::QuantumCircuit::addOperation(qc::QuantumComputation& qc, std::vector qubits{}; for (const auto qubit : qargs) { auto target = qubitMap[qubit].cast(); - qubits.emplace_back(Control{target}); + qubits.emplace_back(target); } auto target = qubits.back().qubit; qubits.pop_back(); @@ -328,11 +328,9 @@ void qc::qiskit::QuantumCircuit::addOperation(qc::QuantumComputation& qc, std::transform(parameters.cbegin(), parameters.cend(), std::back_inserter(fpParams), [](const auto& p) { return std::get(p); }); - qc.emplace_back(qc.getNqubits(), controls, target, type, - fpParams); + qc.emplace_back(controls, target, type, fpParams); } else { - qc.emplace_back(qc.getNqubits(), controls, target, type, - parameters); + qc.emplace_back(controls, target, type, parameters); for (const auto& p : parameters) { qc.addVariables(p); } @@ -345,7 +343,7 @@ void qc::qiskit::QuantumCircuit::addTwoTargetOperation( std::vector qubits{}; for (const auto qubit : qargs) { auto target = qubitMap[qubit].cast(); - qubits.emplace_back(Control{target}); + qubits.emplace_back(target); } auto target1 = qubits.back().qubit; qubits.pop_back(); @@ -364,11 +362,11 @@ void qc::qiskit::QuantumCircuit::addTwoTargetOperation( std::transform(parameters.cbegin(), parameters.cend(), std::back_inserter(fpParams), [](const auto& p) { return std::get(p); }); - qc.emplace_back(qc.getNqubits(), controls, target0, - target1, type, fpParams); + qc.emplace_back(controls, target0, target1, type, + fpParams); } else { - qc.emplace_back(qc.getNqubits(), controls, target0, - target1, type, parameters); + qc.emplace_back(controls, target0, target1, type, + parameters); for (const auto& p : parameters) { qc.addVariables(p); } diff --git a/test/dd/test_dd_functionality.cpp b/test/dd/test_dd_functionality.cpp index 31ef6e14f..dfb7c96cc 100644 --- a/test/dd/test_dd_functionality.cpp +++ b/test/dd/test_dd_functionality.cpp @@ -67,22 +67,21 @@ TEST_P(DDFunctionality, standardOpBuildInverseBuild) { qc::StandardOperation op; switch (gate) { case qc::GPhase: - op = qc::StandardOperation(nqubits, Controls{}, Targets{}, gate, + op = qc::StandardOperation(Controls{}, Targets{}, gate, std::vector{dist(mt)}); break; case qc::U: - op = qc::StandardOperation(nqubits, 0, gate, + op = qc::StandardOperation(0, gate, std::vector{dist(mt), dist(mt), dist(mt)}); break; case qc::U2: - op = qc::StandardOperation(nqubits, 0, gate, - std::vector{dist(mt), dist(mt)}); + op = qc::StandardOperation(0, gate, std::vector{dist(mt), dist(mt)}); break; case qc::RX: case qc::RY: case qc::RZ: case qc::P: - op = qc::StandardOperation(nqubits, 0, gate, std::vector{dist(mt)}); + op = qc::StandardOperation(0, gate, std::vector{dist(mt)}); break; case qc::SWAP: @@ -92,22 +91,21 @@ TEST_P(DDFunctionality, standardOpBuildInverseBuild) { case qc::ECR: case qc::Peres: case qc::Peresdg: - op = qc::StandardOperation(nqubits, {}, 0, 1, gate); + op = qc::StandardOperation({}, 0, 1, gate); break; case qc::RXX: case qc::RYY: case qc::RZZ: case qc::RZX: - op = qc::StandardOperation(nqubits, Controls{}, 0, 1, gate, - std::vector{dist(mt)}); + op = qc::StandardOperation(Controls{}, 0, 1, gate, std::vector{dist(mt)}); break; case qc::XXminusYY: case qc::XXplusYY: - op = qc::StandardOperation(nqubits, Controls{}, 0, 1, gate, + op = qc::StandardOperation(Controls{}, 0, 1, gate, std::vector{dist(mt), dist(mt)}); break; default: - op = qc::StandardOperation(nqubits, 0, gate); + op = qc::StandardOperation(0, gate); } ASSERT_NO_THROW( @@ -124,22 +122,21 @@ TEST_P(DDFunctionality, controlledStandardOpBuildInverseBuild) { qc::StandardOperation op; switch (gate) { case qc::GPhase: - op = qc::StandardOperation(nqubits, Controls{0}, Targets{}, gate, + op = qc::StandardOperation(Controls{0}, Targets{}, gate, std::vector{dist(mt)}); break; case qc::U: - op = qc::StandardOperation(nqubits, 0, 1, gate, + op = qc::StandardOperation(0, 1, gate, std::vector{dist(mt), dist(mt), dist(mt)}); break; case qc::U2: - op = qc::StandardOperation(nqubits, 0, 1, gate, - std::vector{dist(mt), dist(mt)}); + op = qc::StandardOperation(0, 1, gate, std::vector{dist(mt), dist(mt)}); break; case qc::RX: case qc::RY: case qc::RZ: case qc::P: - op = qc::StandardOperation(nqubits, 0, 1, gate, std::vector{dist(mt)}); + op = qc::StandardOperation(0, 1, gate, std::vector{dist(mt)}); break; case qc::SWAP: @@ -149,22 +146,21 @@ TEST_P(DDFunctionality, controlledStandardOpBuildInverseBuild) { case qc::ECR: case qc::Peres: case qc::Peresdg: - op = qc::StandardOperation(nqubits, Controls{0}, 1, 2, gate); + op = qc::StandardOperation(Controls{0}, 1, 2, gate); break; case qc::RXX: case qc::RYY: case qc::RZZ: case qc::RZX: - op = qc::StandardOperation(nqubits, Controls{0}, 1, 2, gate, - std::vector{dist(mt)}); + op = qc::StandardOperation(Controls{0}, 1, 2, gate, std::vector{dist(mt)}); break; case qc::XXminusYY: case qc::XXplusYY: - op = qc::StandardOperation(nqubits, Controls{0}, 1, 2, gate, + op = qc::StandardOperation(Controls{0}, 1, 2, gate, std::vector{dist(mt), dist(mt)}); break; default: - op = qc::StandardOperation(nqubits, 0, 1, gate); + op = qc::StandardOperation(0, 1, gate); } ASSERT_NO_THROW( @@ -181,23 +177,22 @@ TEST_P(DDFunctionality, controlledStandardNegOpBuildInverseBuild) { qc::StandardOperation op; switch (gate) { case qc::GPhase: - op = qc::StandardOperation(nqubits, Controls{0_nc}, Targets{}, gate, + op = qc::StandardOperation(Controls{0_nc}, Targets{}, gate, std::vector{dist(mt)}); break; case qc::U: - op = qc::StandardOperation(nqubits, Controls{0_nc}, 1, gate, + op = qc::StandardOperation(Controls{0_nc}, 1, gate, std::vector{dist(mt), dist(mt), dist(mt)}); break; case qc::U2: - op = qc::StandardOperation(nqubits, Controls{0_nc}, 1, gate, + op = qc::StandardOperation(Controls{0_nc}, 1, gate, std::vector{dist(mt), dist(mt)}); break; case qc::RX: case qc::RY: case qc::RZ: case qc::P: - op = qc::StandardOperation(nqubits, Controls{0_nc}, 1, gate, - std::vector{dist(mt)}); + op = qc::StandardOperation(Controls{0_nc}, 1, gate, std::vector{dist(mt)}); break; case qc::SWAP: @@ -207,22 +202,22 @@ TEST_P(DDFunctionality, controlledStandardNegOpBuildInverseBuild) { case qc::ECR: case qc::Peres: case qc::Peresdg: - op = qc::StandardOperation(nqubits, Controls{0_nc}, 1, 2, gate); + op = qc::StandardOperation(Controls{0_nc}, 1, 2, gate); break; case qc::RXX: case qc::RYY: case qc::RZZ: case qc::RZX: - op = qc::StandardOperation(nqubits, Controls{0_nc}, 1, 2, gate, + op = qc::StandardOperation(Controls{0_nc}, 1, 2, gate, std::vector{dist(mt)}); break; case qc::XXminusYY: case qc::XXplusYY: - op = qc::StandardOperation(nqubits, Controls{0_nc}, 1, 2, gate, + op = qc::StandardOperation(Controls{0_nc}, 1, 2, gate, std::vector{dist(mt), dist(mt)}); break; default: - op = qc::StandardOperation(nqubits, Controls{0_nc}, 1, gate); + op = qc::StandardOperation(Controls{0_nc}, 1, gate); } ASSERT_NO_THROW( @@ -314,7 +309,7 @@ TEST_F(DDFunctionality, buildCircuit) { TEST_F(DDFunctionality, nonUnitary) { const qc::QuantumComputation qc{}; auto dummyMap = Permutation{}; - auto op = qc::NonUnitaryOperation(nqubits, {0, 1, 2, 3}, {0, 1, 2, 3}); + auto op = qc::NonUnitaryOperation({0, 1, 2, 3}, {0, 1, 2, 3}); EXPECT_FALSE(op.isUnitary()); EXPECT_THROW(getDD(&op, *dd), qc::QFRException); EXPECT_THROW(getInverseDD(&op, *dd), qc::QFRException); @@ -327,8 +322,7 @@ TEST_F(DDFunctionality, nonUnitary) { for (Qubit i = 0; i < nqubits; ++i) { dummyMap[i] = i; } - auto barrier = - qc::StandardOperation(nqubits, {0, 1, 2, 3}, qc::OpType::Barrier); + auto barrier = qc::StandardOperation({0, 1, 2, 3}, qc::OpType::Barrier); EXPECT_TRUE(getDD(&barrier, *dd).isIdentity()); EXPECT_TRUE(getInverseDD(&barrier, *dd).isIdentity()); EXPECT_TRUE(getDD(&barrier, *dd, dummyMap).isIdentity()); diff --git a/test/dd/test_dd_noise_functionality.cpp b/test/dd/test_dd_noise_functionality.cpp index 424399261..8a0c4a0a5 100644 --- a/test/dd/test_dd_noise_functionality.cpp +++ b/test/dd/test_dd_noise_functionality.cpp @@ -4,7 +4,6 @@ #include "dd/Operations.hpp" #include "gtest/gtest.h" -#include using namespace qc; @@ -285,24 +284,24 @@ TEST_F(DDNoiseFunctionalityTest, StochSimulateAdder4IdentiyError) { TEST_F(DDNoiseFunctionalityTest, testingUsedQubits) { const std::size_t nqubits = 1; - auto standardOp = StandardOperation(nqubits, 1, qc::Z); + auto standardOp = StandardOperation(1, qc::Z); EXPECT_EQ(standardOp.getUsedQubits().size(), 1); EXPECT_TRUE(standardOp.getUsedQubits().count(1)); - auto nonUnitaryOp = NonUnitaryOperation(nqubits, 0, 0); + auto nonUnitaryOp = NonUnitaryOperation(0, 0); EXPECT_EQ(nonUnitaryOp.getUsedQubits().size(), 1); EXPECT_TRUE(nonUnitaryOp.getUsedQubits().count(0) == 1U); - auto compoundOp = qc::CompoundOperation(nqubits); - compoundOp.emplace_back(nqubits, 0, qc::Z); - compoundOp.emplace_back(nqubits, 1, qc::H); - compoundOp.emplace_back(nqubits, 0, qc::X); + auto compoundOp = qc::CompoundOperation(); + compoundOp.emplace_back(0, qc::Z); + compoundOp.emplace_back(1, qc::H); + compoundOp.emplace_back(0, qc::X); EXPECT_EQ(compoundOp.getUsedQubits().size(), 2); EXPECT_TRUE(compoundOp.getUsedQubits().count(0)); EXPECT_TRUE(compoundOp.getUsedQubits().count(1)); std::unique_ptr xOp = - std::make_unique(nqubits, 0, qc::X); + std::make_unique(0, qc::X); auto classicalControlledOp = qc::ClassicControlledOperation(xOp, std::pair{0, nqubits}, 1U); EXPECT_EQ(classicalControlledOp.getUsedQubits().size(), 1); diff --git a/test/python/test_qiskit.py b/test/python/test_qiskit.py index 0e6c27bcb..26a1dcfc8 100644 --- a/test/python/test_qiskit.py +++ b/test/python/test_qiskit.py @@ -34,7 +34,6 @@ def test_single_gate() -> None: assert mqt_qc.num_qubits == 1 assert mqt_qc.num_ops == 1 assert mqt_qc[0].name.strip() == "h" - assert mqt_qc[0].num_qubits == 1 def test_two_qubit_gate() -> None: @@ -46,7 +45,6 @@ def test_two_qubit_gate() -> None: assert mqt_qc.num_qubits == 2 assert mqt_qc.num_ops == 1 assert mqt_qc[0].name.strip() == "x" - assert mqt_qc[0].num_qubits == 2 assert {control.qubit for control in mqt_qc[0].controls} == {0} @@ -59,7 +57,6 @@ def test_mcx() -> None: assert mqt_qc.num_qubits == 3 assert mqt_qc.num_ops == 1 assert mqt_qc[0].name.strip() == "x" - assert mqt_qc[0].num_qubits == 3 assert {control.qubit for control in mqt_qc[0].controls} == {0, 1} @@ -72,7 +69,6 @@ def test_mcx_recursive() -> None: assert mqt_qc.num_qubits == 9 assert mqt_qc.num_ops == 1 assert mqt_qc[0].name.strip() == "x" - assert mqt_qc[0].num_qubits == 9 assert {control.qubit for control in mqt_qc[0].controls} == {0, 1, 2, 3, 4, 5, 6} assert not mqt_qc[0].acts_on(8) @@ -86,7 +82,6 @@ def test_small_mcx_recursive() -> None: assert mqt_qc.num_qubits == 5 assert mqt_qc.num_ops == 1 assert mqt_qc[0].name.strip() == "x" - assert mqt_qc[0].num_qubits == 5 assert {control.qubit for control in mqt_qc[0].controls} == {0, 1, 2, 3} @@ -99,7 +94,6 @@ def test_mcx_vchain() -> None: assert mqt_qc.num_qubits == 9 assert mqt_qc.num_ops == 1 assert mqt_qc[0].name.strip() == "x" - assert mqt_qc[0].num_qubits == 9 assert {control.qubit for control in mqt_qc[0].controls} == {0, 1, 2, 3, 4} for i in range(6, 9): assert not mqt_qc[0].acts_on(i) @@ -124,9 +118,6 @@ def test_custom_gate() -> None: assert mqt_qc[0][1].name.strip() == "x" assert mqt_qc[0][2].name.strip() == "x" assert mqt_qc[0][3].name.strip() == "measure" - assert mqt_qc[0][0].num_qubits == 3 - assert mqt_qc[0][1].num_qubits == 3 - assert mqt_qc[0][1].num_qubits == 3 assert {control.qubit for control in mqt_qc[0][1].controls} == {0} assert {control.qubit for control in mqt_qc[0][2].controls} == {0} diff --git a/test/unittests/test_ecc_functionality.cpp b/test/unittests/test_ecc_functionality.cpp index 4616f08a1..a09164622 100644 --- a/test/unittests/test_ecc_functionality.cpp +++ b/test/unittests/test_ecc_functionality.cpp @@ -173,8 +173,7 @@ class DDECCFunctionalityTest : public ::testing::Test { auto initialQuit = qcMapped->begin(); qcMapped->insert( initialQuit + static_cast(insertErrorAfterNGates), - std::make_unique(qcMapped->getNqubits(), - std::vector{target}, + std::make_unique(std::vector{target}, qc::Reset)); auto result = simulateAndVerifyResults(qcOriginal, qcMapped, simulateWithErrors, diff --git a/test/unittests/test_io.cpp b/test/unittests/test_io.cpp index 096bea6ed..edac3c934 100644 --- a/test/unittests/test_io.cpp +++ b/test/unittests/test_io.cpp @@ -402,7 +402,7 @@ TEST_F(IO, printingNonUnitary) { EXPECT_NO_THROW(qc->import(ss, qc::Format::OpenQASM3)); std::cout << *qc << "\n"; for (const auto& op : *qc) { - op->print(std::cout); + op->print(std::cout, qc->getNqubits()); std::cout << "\n"; } } diff --git a/test/unittests/test_qfr_functionality.cpp b/test/unittests/test_qfr_functionality.cpp index 40f5e0022..fccb7c521 100644 --- a/test/unittests/test_qfr_functionality.cpp +++ b/test/unittests/test_qfr_functionality.cpp @@ -861,14 +861,12 @@ TEST_F(QFRFunctionality, eliminateResetsBasicTest) { const auto& op2 = qc.at(2); const auto& op3 = qc.at(3); - EXPECT_EQ(op0->getNqubits(), 2); EXPECT_TRUE(op0->getType() == qc::H); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(0)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 2); EXPECT_TRUE(op1->getType() == qc::Measure); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); @@ -879,14 +877,12 @@ TEST_F(QFRFunctionality, eliminateResetsBasicTest) { EXPECT_EQ(classics0.size(), 1); EXPECT_EQ(classics0.at(0), 0); - EXPECT_EQ(op2->getNqubits(), 2); EXPECT_TRUE(op2->getType() == qc::H); const auto& targets2 = op2->getTargets(); EXPECT_EQ(targets2.size(), 1); EXPECT_EQ(targets2.at(0), static_cast(1)); EXPECT_TRUE(op2->getControls().empty()); - EXPECT_EQ(op3->getNqubits(), 2); EXPECT_TRUE(op3->getType() == qc::Measure); const auto& targets3 = op3->getTargets(); EXPECT_EQ(targets3.size(), 1); @@ -920,14 +916,12 @@ TEST_F(QFRFunctionality, eliminateResetsClassicControlled) { const auto& op1 = qc.at(1); const auto& op2 = qc.at(2); - EXPECT_EQ(op0->getNqubits(), 2); EXPECT_TRUE(op0->getType() == qc::H); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(0)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 2); EXPECT_TRUE(op1->getType() == qc::Measure); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); @@ -938,13 +932,11 @@ TEST_F(QFRFunctionality, eliminateResetsClassicControlled) { EXPECT_EQ(classics0.size(), 1); EXPECT_EQ(classics0.at(0), 0); - EXPECT_EQ(op2->getNqubits(), 2); EXPECT_TRUE(op2->isClassicControlledOperation()); auto* classicControlled = dynamic_cast(op2.get()); ASSERT_NE(classicControlled, nullptr); const auto& operation = classicControlled->getOperation(); - EXPECT_EQ(operation->getNqubits(), 2); EXPECT_TRUE(operation->getType() == qc::X); EXPECT_EQ(classicControlled->getNtargets(), 1); const auto& targets = classicControlled->getTargets(); @@ -974,21 +966,18 @@ TEST_F(QFRFunctionality, eliminateResetsMultipleTargetReset) { const auto& op1 = qc.at(1); const auto& op2 = qc.at(2); - EXPECT_EQ(op0->getNqubits(), 4); EXPECT_TRUE(op0->getType() == qc::X); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(2)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 4); EXPECT_TRUE(op1->getType() == qc::Z); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); EXPECT_EQ(targets1.at(0), static_cast(3)); EXPECT_TRUE(op1->getControls().empty()); - EXPECT_EQ(op2->getNqubits(), 4); EXPECT_TRUE(op2->getType() == qc::X); const auto& targets2 = op2->getTargets(); EXPECT_EQ(targets2.size(), 1); @@ -1024,7 +1013,6 @@ TEST_F(QFRFunctionality, eliminateResetsCompoundOperation) { const auto& op = qc.at(0); EXPECT_TRUE(op->isCompoundOperation()); - EXPECT_EQ(op->getNqubits(), 5); auto* compOp0 = dynamic_cast(op.get()); ASSERT_NE(compOp0, nullptr); EXPECT_EQ(compOp0->size(), 3); @@ -1033,7 +1021,6 @@ TEST_F(QFRFunctionality, eliminateResetsCompoundOperation) { const auto& op1 = compOp0->at(1); const auto& op2 = compOp0->at(2); - EXPECT_EQ(op0->getNqubits(), 5); EXPECT_TRUE(op0->getType() == qc::X); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); @@ -1042,7 +1029,6 @@ TEST_F(QFRFunctionality, eliminateResetsCompoundOperation) { EXPECT_EQ(controls0.size(), 1); EXPECT_EQ(controls0.count(3), 1); - EXPECT_EQ(op1->getNqubits(), 5); EXPECT_TRUE(op1->getType() == qc::Measure); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); @@ -1053,13 +1039,11 @@ TEST_F(QFRFunctionality, eliminateResetsCompoundOperation) { EXPECT_EQ(classics0.size(), 1); EXPECT_EQ(classics0.at(0), 0); - EXPECT_EQ(op2->getNqubits(), 5); EXPECT_TRUE(op2->isClassicControlledOperation()); auto* classicControlled = dynamic_cast(op2.get()); ASSERT_NE(classicControlled, nullptr); const auto& operation = classicControlled->getOperation(); - EXPECT_EQ(operation->getNqubits(), 5); EXPECT_TRUE(operation->getType() == qc::X); EXPECT_EQ(classicControlled->getNtargets(), 1); const auto& targets = classicControlled->getTargets(); @@ -1104,14 +1088,12 @@ TEST_F(QFRFunctionality, deferMeasurementsBasicTest) { const auto& op1 = qc.at(1); const auto& op2 = qc.at(2); - EXPECT_EQ(op0->getNqubits(), 2); EXPECT_TRUE(op0->getType() == qc::H); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(0)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 2); EXPECT_TRUE(op1->getType() == qc::X); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); @@ -1120,7 +1102,6 @@ TEST_F(QFRFunctionality, deferMeasurementsBasicTest) { EXPECT_EQ(controls1.size(), 1); EXPECT_EQ(controls1.count(0), 1); - EXPECT_EQ(op2->getNqubits(), 2); ASSERT_TRUE(op2->getType() == qc::Measure); const auto& targets2 = op2->getTargets(); EXPECT_EQ(targets2.size(), 1); @@ -1174,14 +1155,12 @@ TEST_F(QFRFunctionality, const auto& op2 = qc.at(2); const auto& op3 = qc.at(3); - EXPECT_EQ(op0->getNqubits(), 2); EXPECT_TRUE(op0->getType() == qc::H); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(0)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 2); EXPECT_TRUE(op1->getType() == qc::X); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); @@ -1190,14 +1169,12 @@ TEST_F(QFRFunctionality, EXPECT_EQ(controls1.size(), 1); EXPECT_EQ(controls1.count(0), 1); - EXPECT_EQ(op2->getNqubits(), 2); EXPECT_TRUE(op2->getType() == qc::H); const auto& targets2 = op2->getTargets(); EXPECT_EQ(targets2.size(), 1); EXPECT_EQ(targets2.at(0), static_cast(0)); EXPECT_TRUE(op2->getControls().empty()); - EXPECT_EQ(op3->getNqubits(), 2); ASSERT_TRUE(op3->getType() == qc::Measure); const auto& targets3 = op3->getTargets(); EXPECT_EQ(targets3.size(), 1); @@ -1255,14 +1232,12 @@ TEST_F(QFRFunctionality, deferMeasurementsTwoClassic) { const auto& op3 = qc.at(3); const auto& op4 = qc.at(4); - EXPECT_EQ(op0->getNqubits(), 2); EXPECT_TRUE(op0->getType() == qc::H); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(0)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 2); EXPECT_TRUE(op1->getType() == qc::X); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); @@ -1271,7 +1246,6 @@ TEST_F(QFRFunctionality, deferMeasurementsTwoClassic) { EXPECT_EQ(controls1.size(), 1); EXPECT_EQ(controls1.count(0), 1); - EXPECT_EQ(op2->getNqubits(), 2); EXPECT_TRUE(op2->getType() == qc::Z); const auto& targets2 = op2->getTargets(); EXPECT_EQ(targets2.size(), 1); @@ -1280,14 +1254,12 @@ TEST_F(QFRFunctionality, deferMeasurementsTwoClassic) { EXPECT_EQ(controls2.size(), 1); EXPECT_EQ(controls2.count(0), 1); - EXPECT_EQ(op3->getNqubits(), 2); EXPECT_TRUE(op3->getType() == qc::H); const auto& targets3 = op3->getTargets(); EXPECT_EQ(targets3.size(), 1); EXPECT_EQ(targets3.at(0), static_cast(0)); EXPECT_TRUE(op3->getControls().empty()); - EXPECT_EQ(op4->getNqubits(), 2); ASSERT_TRUE(op4->getType() == qc::Measure); const auto& targets4 = op4->getTargets(); EXPECT_EQ(targets4.size(), 1); @@ -1340,21 +1312,18 @@ TEST_F(QFRFunctionality, deferMeasurementsCorrectOrder) { const auto& op2 = qc.at(2); const auto& op3 = qc.at(3); - EXPECT_EQ(op0->getNqubits(), 2); EXPECT_TRUE(op0->getType() == qc::H); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(0)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 2); EXPECT_TRUE(op1->getType() == qc::H); const auto& targets1 = op2->getTargets(); EXPECT_EQ(targets1.size(), 1); EXPECT_EQ(targets1.at(0), static_cast(1)); EXPECT_TRUE(op1->getControls().empty()); - EXPECT_EQ(op2->getNqubits(), 2); EXPECT_TRUE(op2->getType() == qc::X); const auto& targets2 = op1->getTargets(); EXPECT_EQ(targets2.size(), 1); @@ -1363,7 +1332,6 @@ TEST_F(QFRFunctionality, deferMeasurementsCorrectOrder) { EXPECT_EQ(controls2.size(), 1); EXPECT_EQ(controls2.count(0), 1); - EXPECT_EQ(op3->getNqubits(), 2); ASSERT_TRUE(op3->getType() == qc::Measure); const auto& targets3 = op3->getTargets(); EXPECT_EQ(targets3.size(), 1); @@ -1420,21 +1388,18 @@ TEST_F(QFRFunctionality, deferMeasurementsTwoClassicCorrectOrder) { const auto& op3 = qc.at(3); const auto& op4 = qc.at(4); - EXPECT_EQ(op0->getNqubits(), 2); EXPECT_TRUE(op0->getType() == qc::H); const auto& targets0 = op0->getTargets(); EXPECT_EQ(targets0.size(), 1); EXPECT_EQ(targets0.at(0), static_cast(0)); EXPECT_TRUE(op0->getControls().empty()); - EXPECT_EQ(op1->getNqubits(), 2); EXPECT_TRUE(op1->getType() == qc::H); const auto& targets1 = op1->getTargets(); EXPECT_EQ(targets1.size(), 1); EXPECT_EQ(targets1.at(0), static_cast(1)); EXPECT_TRUE(op1->getControls().empty()); - EXPECT_EQ(op2->getNqubits(), 2); EXPECT_TRUE(op2->getType() == qc::X); const auto& targets2 = op2->getTargets(); EXPECT_EQ(targets2.size(), 1); @@ -1443,7 +1408,6 @@ TEST_F(QFRFunctionality, deferMeasurementsTwoClassicCorrectOrder) { EXPECT_EQ(controls2.size(), 1); EXPECT_EQ(controls2.count(0), 1); - EXPECT_EQ(op3->getNqubits(), 2); EXPECT_TRUE(op3->getType() == qc::Z); const auto& targets3 = op3->getTargets(); EXPECT_EQ(targets3.size(), 1); @@ -1452,7 +1416,6 @@ TEST_F(QFRFunctionality, deferMeasurementsTwoClassicCorrectOrder) { EXPECT_EQ(controls3.size(), 1); EXPECT_EQ(controls3.count(0), 1); - EXPECT_EQ(op4->getNqubits(), 2); ASSERT_TRUE(op4->getType() == qc::Measure); const auto& targets4 = op4->getTargets(); EXPECT_EQ(targets4.size(), 1); @@ -1565,15 +1528,15 @@ TEST_F(QFRFunctionality, FlattenRecursive) { } TEST_F(QFRFunctionality, OperationEquality) { - const auto x = StandardOperation(1U, 0, qc::X); - const auto z = StandardOperation(1U, 0, qc::Z); + const auto x = StandardOperation(0, qc::X); + const auto z = StandardOperation(0, qc::Z); EXPECT_TRUE(x.equals(x)); EXPECT_EQ(x, x); EXPECT_FALSE(x.equals(z)); EXPECT_NE(x, z); - const auto x0 = StandardOperation(2U, 0, qc::X); - const auto x1 = StandardOperation(2U, 1, qc::X); + const auto x0 = StandardOperation(0, qc::X); + const auto x1 = StandardOperation(1, qc::X); EXPECT_FALSE(x0.equals(x1)); EXPECT_NE(x0, x1); Permutation perm0{}; @@ -1582,21 +1545,21 @@ TEST_F(QFRFunctionality, OperationEquality) { EXPECT_TRUE(x0.equals(x1, perm0, {})); EXPECT_TRUE(x0.equals(x1, {}, perm0)); - const auto cx01 = StandardOperation(2U, 0, 1, qc::X); - const auto cx10 = StandardOperation(2U, 1, 0, qc::X); + const auto cx01 = StandardOperation(0, 1, qc::X); + const auto cx10 = StandardOperation(1, 0, qc::X); EXPECT_FALSE(cx01.equals(cx10)); EXPECT_NE(cx01, cx10); EXPECT_FALSE(x0.equals(cx01)); EXPECT_NE(x0, cx01); - const auto p = StandardOperation(1U, 0, qc::P, {2.0}); - const auto pm = StandardOperation(1U, 0, qc::P, {-2.0}); + const auto p = StandardOperation(0, qc::P, {2.0}); + const auto pm = StandardOperation(0, qc::P, {-2.0}); EXPECT_FALSE(p.equals(pm)); EXPECT_NE(p, pm); - const auto measure0 = NonUnitaryOperation(2U, 0, 0U); - const auto measure1 = NonUnitaryOperation(2U, 0, 1U); - const auto measure2 = NonUnitaryOperation(2U, 1, 0U); + const auto measure0 = NonUnitaryOperation(0, 0U); + const auto measure1 = NonUnitaryOperation(0, 1U); + const auto measure2 = NonUnitaryOperation(1, 0U); EXPECT_FALSE(measure0.equals(x0)); EXPECT_NE(measure0, x0); EXPECT_TRUE(measure0.equals(measure0)); @@ -1614,19 +1577,18 @@ TEST_F(QFRFunctionality, OperationEquality) { const auto expectedValue1 = 1U; std::unique_ptr xp0 = - std::make_unique(1U, 0, qc::X); + std::make_unique(0, qc::X); std::unique_ptr xp1 = - std::make_unique(1U, 0, qc::X); + std::make_unique(0, qc::X); std::unique_ptr xp2 = - std::make_unique(1U, 0, qc::X); + std::make_unique(0, qc::X); const auto classic0 = ClassicControlledOperation(xp0, controlRegister0, expectedValue0); const auto classic1 = ClassicControlledOperation(xp1, controlRegister0, expectedValue1); const auto classic2 = ClassicControlledOperation(xp2, controlRegister1, expectedValue0); - std::unique_ptr zp = - std::make_unique(1U, 0, qc::Z); + std::unique_ptr zp = std::make_unique(0, qc::Z); const auto classic3 = ClassicControlledOperation(zp, controlRegister0, expectedValue0); EXPECT_FALSE(classic0.equals(x)); @@ -1640,15 +1602,15 @@ TEST_F(QFRFunctionality, OperationEquality) { EXPECT_FALSE(classic0.equals(classic3)); EXPECT_NE(classic0, classic3); - auto compound0 = CompoundOperation(1U); - compound0.emplace_back(1U, 0, qc::X); + auto compound0 = CompoundOperation(); + compound0.emplace_back(0, qc::X); - auto compound1 = CompoundOperation(1U); - compound1.emplace_back(1U, 0, qc::X); - compound1.emplace_back(1U, 0, qc::Z); + auto compound1 = CompoundOperation(); + compound1.emplace_back(0, qc::X); + compound1.emplace_back(0, qc::Z); - auto compound2 = CompoundOperation(1U); - compound2.emplace_back(1U, 0, qc::Z); + auto compound2 = CompoundOperation(); + compound2.emplace_back(0, qc::Z); EXPECT_FALSE(compound0.equals(x)); EXPECT_NE(compound0, x); @@ -1842,7 +1804,6 @@ TEST_F(QFRFunctionality, CircuitToOperation) { qc.x(0); const auto& op = qc.asOperation(); EXPECT_EQ(op->getType(), qc::X); - EXPECT_EQ(op->getNqubits(), 2U); EXPECT_EQ(op->getNcontrols(), 0U); EXPECT_EQ(op->getTargets().front(), 0U); EXPECT_TRUE(qc.empty()); @@ -1851,7 +1812,6 @@ TEST_F(QFRFunctionality, CircuitToOperation) { qc.classicControlled(qc::X, 0, 1, {0, 1U}, 1U); const auto& op2 = qc.asOperation(); EXPECT_EQ(op2->getType(), qc::Compound); - EXPECT_EQ(op2->getNqubits(), 2U); EXPECT_TRUE(qc.empty()); } @@ -1975,8 +1935,7 @@ TEST_F(QFRFunctionality, OpNameToTypeSimple) { TEST_F(QFRFunctionality, dumpAndImportTeleportation) { QuantumComputation qc(3); - qc.emplace_back(3, Targets{0, 1, 2}, - OpType::Teleportation); + qc.emplace_back(Targets{0, 1, 2}, OpType::Teleportation); std::stringstream ss; qc.dumpOpenQASM2(ss); EXPECT_TRUE(ss.str().find("teleport") != std::string::npos); @@ -1988,7 +1947,7 @@ TEST_F(QFRFunctionality, dumpAndImportTeleportation) { } TEST_F(QFRFunctionality, addControlStandardOperation) { - auto op = StandardOperation(3, 0, OpType::X); + auto op = StandardOperation(0, OpType::X); op.addControl(1); op.addControl(2); ASSERT_EQ(op.getNcontrols(), 2); @@ -2007,7 +1966,7 @@ TEST_F(QFRFunctionality, addControlStandardOperation) { } TEST_F(QFRFunctionality, addControlSymbolicOperation) { - auto op = SymbolicOperation(3, 0, OpType::X); + auto op = SymbolicOperation(0, OpType::X); op.addControl(1); op.addControl(2); @@ -2027,8 +1986,7 @@ TEST_F(QFRFunctionality, addControlSymbolicOperation) { } TEST_F(QFRFunctionality, addControlClassicControlledOperation) { - std::unique_ptr xp = - std::make_unique(1U, 0, qc::X); + std::unique_ptr xp = std::make_unique(0, qc::X); const auto controlRegister = qc::QuantumRegister{0, 1U}; const auto expectedValue = 0U; auto op = ClassicControlledOperation(xp, controlRegister, expectedValue); @@ -2050,7 +2008,7 @@ TEST_F(QFRFunctionality, addControlClassicControlledOperation) { } TEST_F(QFRFunctionality, addControlNonUnitaryOperation) { - auto op = NonUnitaryOperation(1U, 0U, Measure); + auto op = NonUnitaryOperation(0U, Measure); EXPECT_THROW(static_cast(op.getControls()), QFRException); EXPECT_THROW(op.addControl(1), QFRException); @@ -2062,13 +2020,13 @@ TEST_F(QFRFunctionality, addControlNonUnitaryOperation) { } TEST_F(QFRFunctionality, addControlCompundOperation) { - auto op = CompoundOperation(4); + auto op = CompoundOperation(); auto control0 = 0U; auto control1 = 1U; - auto xOp = std::make_unique(4, Targets{1}, OpType::X); - auto cxOp = std::make_unique(4, Targets{3}, OpType::X); + auto xOp = std::make_unique(Targets{1}, OpType::X); + auto cxOp = std::make_unique(Targets{3}, OpType::X); cxOp->addControl(control1); op.emplace_back(xOp); @@ -2091,7 +2049,7 @@ TEST_F(QFRFunctionality, addControlTwice) { auto control = 0U; std::unique_ptr op = - std::make_unique(2, Targets{1}, OpType::X); + std::make_unique(Targets{1}, OpType::X); op->addControl(control); EXPECT_THROW(op->addControl(control), QFRException); @@ -2099,7 +2057,7 @@ TEST_F(QFRFunctionality, addControlTwice) { ClassicControlledOperation(op, qc::QuantumRegister{0, 1U}, 0U); EXPECT_THROW(classicControlledOp.addControl(control), QFRException); - auto symbolicOp = SymbolicOperation(2, Targets{1}, OpType::X); + auto symbolicOp = SymbolicOperation(Targets{1}, OpType::X); symbolicOp.addControl(control); EXPECT_THROW(symbolicOp.addControl(control), QFRException); } @@ -2109,24 +2067,24 @@ TEST_F(QFRFunctionality, addTargetAsControl) { auto control = 1U; std::unique_ptr op = - std::make_unique(2, Targets{1}, OpType::X); + std::make_unique(Targets{1}, OpType::X); EXPECT_THROW(op->addControl(control), QFRException); auto classicControlledOp = ClassicControlledOperation(op, qc::QuantumRegister{0, 1U}, 0U); EXPECT_THROW(classicControlledOp.addControl(control), QFRException); - auto symbolicOp = SymbolicOperation(2, Targets{1}, OpType::X); + auto symbolicOp = SymbolicOperation(Targets{1}, OpType::X); EXPECT_THROW(symbolicOp.addControl(control), QFRException); } TEST_F(QFRFunctionality, addControlCompundOperationInvalid) { - auto op = CompoundOperation(4); + auto op = CompoundOperation(); auto control1 = 1U; - auto xOp = std::make_unique(4, Targets{1}, OpType::X); - auto cxOp = std::make_unique(4, Targets{3}, OpType::X); + auto xOp = std::make_unique(Targets{1}, OpType::X); + auto cxOp = std::make_unique(Targets{3}, OpType::X); cxOp->addControl(control1); op.emplace_back(xOp); @@ -2137,7 +2095,7 @@ TEST_F(QFRFunctionality, addControlCompundOperationInvalid) { } TEST_F(QFRFunctionality, invertUnsupportedOperation) { - auto op = NonUnitaryOperation(1U, 0U, OpType::Measure); + auto op = NonUnitaryOperation(0U, OpType::Measure); ASSERT_THROW(op.invert(), QFRException); } @@ -2148,14 +2106,14 @@ TEST_F(QFRFunctionality, invertStandardOpSelfInverting) { }; for (auto opType : opTypes) { - auto op = StandardOperation(1U, 0U, opType); + auto op = StandardOperation(0U, opType); op.invert(); ASSERT_EQ(op.getType(), opType); } } TEST_F(QFRFunctionality, invertStandardOpInvertClone) { - auto op1 = StandardOperation(1U, 0U, S); + auto op1 = StandardOperation(0U, S); auto op2 = op1.getInverted(); ASSERT_EQ(op1.getType(), S); ASSERT_EQ(op2->getType(), Sdg); @@ -2168,11 +2126,11 @@ TEST_F(QFRFunctionality, invertStandardOpSpecial) { }; for (const auto& [opType, opTypeInv] : opTypes) { - auto op = StandardOperation(1U, 0U, opType); + auto op = StandardOperation(0U, opType); op.invert(); ASSERT_EQ(op.getType(), opTypeInv); - auto op2 = StandardOperation(1U, 0U, opTypeInv); + auto op2 = StandardOperation(0U, opTypeInv); op2.invert(); ASSERT_EQ(op2.getType(), opType); } @@ -2199,23 +2157,23 @@ TEST_F(QFRFunctionality, invertStandardOpParamChange) { for (const auto& testcase : cases) { auto op = - StandardOperation(1U, 0U, std::get<0>(testcase), std::get<1>(testcase)); + StandardOperation(0U, std::get<0>(testcase), std::get<1>(testcase)); op.invert(); ASSERT_EQ(op.getParameter(), std::get<2>(testcase)); } - auto op = StandardOperation(2U, Targets{0U, 1U}, OpType::DCX); + auto op = StandardOperation(Targets{0U, 1U}, OpType::DCX); op.invert(); const auto expectedTargets = Targets{1U, 0U}; ASSERT_EQ(op.getTargets(), expectedTargets); } TEST_F(QFRFunctionality, invertCompoundOperation) { - auto op = CompoundOperation(4); + auto op = CompoundOperation(); - op.emplace_back(4U, 0U, OpType::X); - op.emplace_back(4U, 1U, OpType::RZ, std::vector{1}); - op.emplace_back(4U, 1U, OpType::S); + op.emplace_back(0U, OpType::X); + op.emplace_back(1U, OpType::RZ, std::vector{1}); + op.emplace_back(1U, OpType::S); op.invert(); @@ -2247,7 +2205,7 @@ TEST_F(QFRFunctionality, invertSymbolicOpParamChange) { for (const auto& testcase : cases) { auto op = - SymbolicOperation(1U, 0U, std::get<0>(testcase), std::get<1>(testcase)); + SymbolicOperation(0U, std::get<0>(testcase), std::get<1>(testcase)); op.invert(); for (size_t i = 0; i < std::get<1>(testcase).size(); ++i) { @@ -2256,7 +2214,7 @@ TEST_F(QFRFunctionality, invertSymbolicOpParamChange) { } // The following gate should be handled by the StandardOperation function - auto op = SymbolicOperation(2U, Targets{0U, 1U}, OpType::DCX); + auto op = SymbolicOperation(Targets{0U, 1U}, OpType::DCX); op.invert(); const auto expectedTargets = Targets{1U, 0U}; ASSERT_EQ(op.getTargets(), expectedTargets); @@ -2466,7 +2424,6 @@ TEST_F(QFRFunctionality, StripIdleQubitsInMiddleOfCircuit) { const auto& qregs = qc.getQregs(); ASSERT_EQ(qregs.size(), 1U); const auto& reg = *qregs.begin(); - const auto name = reg.first; ASSERT_EQ(reg.second.first, 0U); ASSERT_EQ(reg.second.second, 5U); const auto& ancRegs = qc.getANCregs(); diff --git a/test/zx/test_zx_functionality.cpp b/test/zx/test_zx_functionality.cpp index 493d84682..c8867bd44 100644 --- a/test/zx/test_zx_functionality.cpp +++ b/test/zx/test_zx_functionality.cpp @@ -108,9 +108,9 @@ TEST_F(ZXFunctionalityTest, complexCircuit) { TEST_F(ZXFunctionalityTest, nestedCompoundGate) { qc = qc::QuantumComputation(1); - auto innerOp = std::make_unique(1, 0, qc::OpType::X); - auto compound1 = std::make_unique(1); - auto compound2 = std::make_unique(1); + auto innerOp = std::make_unique(0, qc::OpType::X); + auto compound1 = std::make_unique(); + auto compound2 = std::make_unique(); compound1->emplace_back(std::move(innerOp)); compound2->emplace_back(std::move(compound1));