Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feature/conjugation box #984

Merged
merged 10 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions pytket/binders/circuit/Circuit/add_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "tket/Circuit/Boxes.hpp"
#include "tket/Circuit/Circuit.hpp"
#include "tket/Circuit/ClassicalExpBox.hpp"
#include "tket/Circuit/ConjugationBox.hpp"
#include "tket/Circuit/DiagonalBox.hpp"
#include "tket/Circuit/Multiplexor.hpp"
#include "tket/Circuit/PauliExpBoxes.hpp"
Expand Down Expand Up @@ -807,6 +808,30 @@ void init_circuit_add_op(py::class_<Circuit, std::shared_ptr<Circuit>> &c) {
":param args: Indices of the qubits to append the box to"
"\n:return: the new :py:class:`Circuit`",
py::arg("box"), py::arg("args"))
.def(
"add_conjugation_box",
[](Circuit *circ, const ConjugationBox &box,
const unit_vector_t &args, const py::kwargs &kwargs) {
return add_box_method(
circ, std::make_shared<ConjugationBox>(box), args, kwargs);
},
"Append a :py:class:`ConjugationBox` to the circuit.\n\n"
":param box: The box to append\n"
":param args: The qubits to append the box to"
"\n:return: the new :py:class:`Circuit`",
py::arg("box"), py::arg("args"))
.def(
"add_conjugation_box",
[](Circuit *circ, const ConjugationBox &box,
const std::vector<unsigned> &args, const py::kwargs &kwargs) {
return add_box_method(
circ, std::make_shared<ConjugationBox>(box), args, kwargs);
},
"Append a :py:class:`ConjugationBox` to the circuit.\n\n"
":param box: The box to append\n"
":param args: Indices of the qubits to append the box to"
"\n:return: the new :py:class:`Circuit`",
py::arg("box"), py::arg("args"))
.def(
"H",
[](Circuit *circ, unsigned qb, const py::kwargs &kwargs) {
Expand Down
31 changes: 31 additions & 0 deletions pytket/binders/circuit/boxes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "binder_json.hpp"
#include "binder_utils.hpp"
#include "tket/Circuit/Circuit.hpp"
#include "tket/Circuit/ConjugationBox.hpp"
#include "tket/Circuit/DiagonalBox.hpp"
#include "tket/Circuit/Multiplexor.hpp"
#include "tket/Circuit/PauliExpBoxes.hpp"
Expand Down Expand Up @@ -691,5 +692,35 @@ void init_boxes(py::module &m) {
.def(
"is_upper_triangle", &DiagonalBox::is_upper_triangle,
":return: the upper_triangle flag");
py::class_<ConjugationBox, std::shared_ptr<ConjugationBox>, Op>(
m, "ConjugationBox",
"A box to express computations that follow the compute-action-uncompute "
"pattern.")
.def(
py::init<
const Op_ptr &, const Op_ptr &, const std::optional<Op_ptr>>(),
"Construct from operations that perform compute, action, and "
"uncompute. All three operations need to be quantum and have the "
"same size.\n\n"
":param compute: the compute operation\n"
":param action: the action operation\n"
":param uncompute: optional uncompute operation, default to "
"compute.dagger(). If provided, the user needs to make sure that "
"uncompute.dagger() and compute have the same unitary.",
py::arg("compute"), py::arg("action"),
py::arg("uncompute") = std::nullopt)
.def(
"get_circuit", [](ConjugationBox &box) { return *box.to_circuit(); },
":return: the :py:class:`Circuit` described by the box")
.def(
"get_compute", &ConjugationBox::get_compute,
":return: the compute operation")
.def(
"get_action", &ConjugationBox::get_action,
":return: the action operation")
.def(
"get_uncompute", &ConjugationBox::get_uncompute,
":return: the uncompute operation. Returns None if the default "
"compute.dagger() is used");
}
} // namespace tket
2 changes: 1 addition & 1 deletion pytket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def package(self):
cmake.install()

def requirements(self):
self.requires("tket/1.2.36@tket/stable")
self.requires("tket/1.2.37@tket/stable")
self.requires("tklog/0.3.3@tket/stable")
self.requires("tkrng/0.3.3@tket/stable")
self.requires("tkassert/0.3.3@tket/stable")
Expand Down
5 changes: 5 additions & 0 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Changelog
Unreleased
----------

Major new features:

* Add ``ConjugationBox`` to express circuits that follow
the compute-action-uncompute pattern.

Minor new features:

* Implement equality checking for all boxes.
Expand Down
14 changes: 14 additions & 0 deletions pytket/tests/circuit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
MultiplexedTensoredU2Box,
StatePreparationBox,
DiagonalBox,
ConjugationBox,
ExpBox,
PauliExpBox,
PauliExpPairBox,
Expand Down Expand Up @@ -565,6 +566,19 @@ def test_boxes() -> None:
d.add_multiplexed_tensored_u2(multiplexor, [3, 2, 1, 0])
assert np.allclose(unitary, comparison)
assert d.n_gates == 23
# ConjugationBox
compute = CircBox(Circuit(3).CX(0, 1).CX(1, 2))
action = CircBox(Circuit(3).H(2))
conj_box1 = ConjugationBox(compute, action)
assert conj_box1.get_compute() == compute
assert conj_box1.get_action() == action
assert conj_box1.get_uncompute() is None
uncompute = CircBox(Circuit(3).CX(1, 2).CX(0, 1))
conj_box2 = ConjugationBox(compute, action, uncompute)
assert conj_box2.get_uncompute() == uncompute
d.add_conjugation_box(conj_box1, [0, 1, 2])
d.add_conjugation_box(conj_box2, [Qubit(0), Qubit(1), Qubit(2)])
assert d.n_gates == 25
assert json_validate(d)


Expand Down
33 changes: 33 additions & 0 deletions schemas/circuit_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,21 @@
"$ref": "#/definitions/matrix",
"description": "Diagonal matrix represented by DiagonalBox."
},
"compute": {
"$ref": "#/definitions/operation",
"description": "Compute operation in ConjugationBox."
},
"action": {
"$ref": "#/definitions/operation",
"description": "Action operation in ConjugationBox."
},
"uncompute": {
"anyOf": [
{"$ref": "#/definitions/operation"},
{"type": "null"}
],
"description": "Uncompute operation in ConjugationBox."
},
"upper_triangle": {
"type": "boolean",
"description": "Indicate whether to implement multiplexors in the DiagonalBox decomposition as an upper triangle."
Expand Down Expand Up @@ -844,6 +859,24 @@
]
}
},
{
"if": {
"properties": {
"type": {
"const": "ConjugationBox"
}
}
},
"then": {
"required": [
"compute",
"action"
],
"optional": [
"uncompute"
]
}
},
{
"if": {
"properties": {
Expand Down
2 changes: 2 additions & 0 deletions tket/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ target_sources(tket
src/Circuit/DiagonalBox.cpp
src/Circuit/ToffoliBox.cpp
src/Circuit/PauliExpBoxes.cpp
src/Circuit/ConjugationBox.cpp
src/Circuit/Simulation/BitOperations.cpp
src/Circuit/Simulation/CircuitSimulator.cpp
src/Circuit/Simulation/DecomposeCircuit.cpp
Expand Down Expand Up @@ -321,6 +322,7 @@ target_sources(tket
include/tket/Circuit/ThreeQubitConversion.hpp
include/tket/Circuit/ToffoliBox.hpp
include/tket/Circuit/PauliExpBoxes.hpp
include/tket/Circuit/ConjugationBox.hpp
include/tket/Circuit/Simulation/CircuitSimulator.hpp
include/tket/Circuit/Simulation/PauliExpBoxUnitaryCalculator.hpp
include/tket/Architecture/Architecture.hpp
Expand Down
2 changes: 1 addition & 1 deletion tket/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

class TketConan(ConanFile):
name = "tket"
version = "1.2.36"
version = "1.2.37"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
82 changes: 82 additions & 0 deletions tket/include/tket/Circuit/ConjugationBox.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2019-2023 Cambridge Quantum Computing
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include "Boxes.hpp"
#include "Circuit.hpp"
#include "tket/Utils/Json.hpp"

namespace tket {
/**
* Box to express computations that follow the compute-action-uncompute pattern
*/
class ConjugationBox : public Box {
public:
/**
* @brief Construct a new ConjugationBox object from operations that perform
* compute, action, and uncompute. All three operations need to have the same
* signature.
*
* @param compute the compute operation
* @param action the action operation
* @param uncompute optional uncompute operation, default to compute.dagger().
* If provided, the user needs to make sure that uncompute.dagger() and
* compute have the same unitary.
*/
explicit ConjugationBox(
const Op_ptr &compute, const Op_ptr &action,
const std::optional<Op_ptr> uncompute = std::nullopt);

/**
* Copy constructor
*/
ConjugationBox(const ConjugationBox &other);
~ConjugationBox() override {}

Op_ptr symbol_substitution(
const SymEngine::map_basic_basic &) const override {
return Op_ptr();
}

SymSet free_symbols() const override { return {}; }

/**
* Equality check between two ConjugationBox instances
*/
bool is_equal(const Op &op_other) const override;

Op_ptr dagger() const override;
Op_ptr transpose() const override;

Op_ptr get_compute() const { return compute_; }
Op_ptr get_action() const { return action_; }
std::optional<Op_ptr> get_uncompute() const { return uncompute_; }

static Op_ptr from_json(const nlohmann::json &j);

static nlohmann::json to_json(const Op_ptr &op);

protected:
void generate_circuit() const override;

ConjugationBox()
: Box(OpType::ConjugationBox), compute_(), action_(), uncompute_() {}

private:
const Op_ptr compute_;
const Op_ptr action_;
const std::optional<Op_ptr> uncompute_;
};
} // namespace tket
5 changes: 5 additions & 0 deletions tket/include/tket/OpType/OpType.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,11 @@ enum class OpType {
*/
DiagonalBox,

/**
* See \ref ConjugationBox
*/
ConjugationBox,

/**
* See \ref ClassicalExpBox
*/
Expand Down
Loading