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

Allow constant ZZPhase fidelity in DecomposeTK2 #1558

Merged
merged 22 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
2 changes: 1 addition & 1 deletion pytket/binders/passes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Transforms::TwoQbFidelities get_fidelities(const py::kwargs &kwargs) {
} else if (kwargstr == "ZZMax_fidelity") {
fid.ZZMax_fidelity = py::cast<double>(kwarg.second);
} else if (kwargstr == "ZZPhase_fidelity") {
fid.ZZPhase_fidelity = py::cast<Func>(kwarg.second);
fid.ZZPhase_fidelity = py::cast<std::variant<double, Func>>(kwarg.second);
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
} else {
throw py::type_error(
"got an unexpected keyword argument '" + kwargstr + "'");
Expand Down
2 changes: 1 addition & 1 deletion pytket/binders/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Transforms::TwoQbFidelities get_fidelities(const py::kwargs &kwargs) {
} else if (kwargstr == "ZZMax_fidelity") {
fid.ZZMax_fidelity = py::cast<double>(kwarg.second);
} else if (kwargstr == "ZZPhase_fidelity") {
fid.ZZPhase_fidelity = py::cast<Func>(kwarg.second);
fid.ZZPhase_fidelity = py::cast<std::variant<double, Func>>(kwarg.second);
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
} else {
throw py::type_error(
"got an unexpected keyword argument '" + kwargstr + "'");
Expand Down
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.3.20@tket/stable")
self.requires("tket/1.3.21@tket/stable")
self.requires("tklog/0.3.3@tket/stable")
self.requires("tkrng/0.3.3@tket/stable")
self.requires("tkassert/0.3.4@tket/stable")
Expand Down
8 changes: 8 additions & 0 deletions pytket/docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Changelog
=========

Unreleased
----------

Features:

* DecomposeTK2 pass can now accept a float for ZZPhase_fidelity.
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
* DecomposeTK2 now has a json representation when it contains no functions.

1.32.0 (September 2024)
-----------------------

Expand Down
12 changes: 12 additions & 0 deletions pytket/tests/passes_serialisation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,18 @@ def nonparam_predicate_dict(name: str) -> Dict[str, Any]:
"AutoRebase": standard_pass_dict(
{"name": "AutoRebase", "basis_allowed": ["H", "TK1", "CX"], "allow_swaps": True}
),
# ZZPhase must be a float and note a function.
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
"DecomposeTK2": standard_pass_dict(
{
"name": "DecomposeTK2",
"fidelities": {
"CX": None,
"ZZMax": 1.0,
"ZZPhase": 0.5,
},
"allow_swaps": True,
}
),
}

# non-parametrized passes that satisfy pass.from_dict(d).to_dict()==d
Expand Down
10 changes: 10 additions & 0 deletions pytket/tests/transform_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,16 @@ def test_DecomposeTK2() -> None:
assert c.n_gates_of_type(OpType.CX) == 0
assert c.n_gates_of_type(OpType.ZZMax) == 3

c = Circuit(2).add_gate(OpType.TK2, [0.5, 0.5, 0.5], [0, 1])
Transform.DecomposeTK2(False, ZZPhase_fidelity=0.8).apply(c)
assert c.n_gates_of_type(OpType.CX) == 0
assert c.n_gates_of_type(OpType.ZZPhase) == 3

c = Circuit(2).add_gate(OpType.TK2, [0.5, 0.5, 0.5], [0, 1])
Transform.DecomposeTK2(False, ZZPhase_fidelity=lambda _: 0.8).apply(c)
assert c.n_gates_of_type(OpType.CX) == 0
assert c.n_gates_of_type(OpType.ZZPhase) == 3


def test_fidelity_KAK() -> None:
c = get_KAK_test_circuit()
Expand Down
5 changes: 5 additions & 0 deletions schemas/compiler_pass_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@
"type": ["number", "null"],
"minimum": 0,
"maximum": 1
},
"ZZPhase": {
"type": ["number", "null"],
"minimum": 0,
"maximum": 1
}
}
},
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.3.20"
version = "1.3.21"
package_type = "library"
license = "Apache 2"
homepage = "https://github.com/CQCL/tket"
Expand Down
3 changes: 2 additions & 1 deletion tket/include/tket/Transformations/Transform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ inline const Transform id =
struct TwoQbFidelities {
std::optional<double> CX_fidelity;
std::optional<double> ZZMax_fidelity;
std::optional<std::function<double(double)>> ZZPhase_fidelity;
std::optional<std::variant<double, std::function<double(double)>>>
ZZPhase_fidelity;
};

} // namespace Transforms
Expand Down
9 changes: 9 additions & 0 deletions tket/include/tket/Utils/Expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@
#include "Json.hpp"
#include "Symbols.hpp"

/** Helper struct for use with std::visit */
johnchildren marked this conversation as resolved.
Show resolved Hide resolved
template <class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20)
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

namespace tket {

/** Representation of a phase as a multiple of \f$ \pi \f$ */
Expand Down
5 changes: 4 additions & 1 deletion tket/src/Predicates/CompilerPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "tket/Predicates/CompilerPass.hpp"

#include <memory>
#include <optional>
#include <tklog/TketLog.hpp>

#include "tket/Mapping/RoutingMethodJson.hpp"
Expand Down Expand Up @@ -393,7 +394,9 @@ void from_json(const nlohmann::json& j, PassPtr& pp) {
content.at("fidelities").at("CX").get<std::optional<double>>();
fid.ZZMax_fidelity =
content.at("fidelities").at("ZZMax").get<std::optional<double>>();
fid.ZZPhase_fidelity = std::nullopt;
fid.ZZPhase_fidelity =
content.at("fidelities")
.value<std::optional<double>>("ZZPhase", std::nullopt);
bool allow_swaps = content.at("allow_swaps").get<bool>();
pp = DecomposeTK2(fid, allow_swaps);
} else if (passname == "PeepholeOptimise2Q") {
Expand Down
13 changes: 12 additions & 1 deletion tket/src/Predicates/PassGenerators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,18 @@ PassPtr DecomposeTK2(const Transforms::TwoQbFidelities& fid, bool allow_swaps) {
j["allow_swaps"] = allow_swaps;
nlohmann::json fid_json;
fid_json["CX"] = fid.CX_fidelity;
fid_json["ZZPhase"] = "SERIALIZATION OF FUNCTIONS IS NOT SUPPORTED";
if (fid.ZZPhase_fidelity.has_value()) {
std::visit(
overloaded{
[&fid_json](double arg) { fid_json["ZZPhase"] = arg; },
[&fid_json](std::function<double(double)>) {
fid_json["ZZPhase"] =
"SERIALIZATION OF FUNCTIONS IS NOT SUPPORTED";
}},
fid.ZZPhase_fidelity.value());
} else {
fid_json["ZZPhase"] = std::nullptr_t{};
cqc-alec marked this conversation as resolved.
Show resolved Hide resolved
}
fid_json["ZZMax"] = fid.ZZMax_fidelity;
j["fidelities"] = fid_json;
return std::make_shared<StandardPass>(precons, t, postcons, j);
Expand Down
17 changes: 15 additions & 2 deletions tket/src/Transformations/Decomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,14 @@ static double best_noise_aware_decomposition(
unsigned max_nzz = fid.ZZMax_fidelity ? 1 : 3;
for (unsigned n_zz = 0; n_zz <= max_nzz; ++n_zz) {
if (n_zz > 0) {
double gate_fid = (*fid.ZZPhase_fidelity)(angles[n_zz - 1]);
double gate_fid = std::visit(
overloaded{// Constant value
[](double arg) { return arg; },
// A value depending on the angle
[angles, n_zz](std::function<double(double)> arg) {
johnchildren marked this conversation as resolved.
Show resolved Hide resolved
return (arg)(angles[n_zz - 1]);
}},
*fid.ZZPhase_fidelity);
if (gate_fid < 0 || gate_fid > 1) {
throw std::domain_error(
"ZZPhase_fidelity returned a value outside of [0, 1].");
Expand Down Expand Up @@ -857,7 +864,13 @@ Transform decompose_TK2(const TwoQbFidelities &fid, bool allow_swaps) {
}
}
if (fid.ZZMax_fidelity && fid.ZZPhase_fidelity) {
if (*fid.ZZMax_fidelity < (*fid.ZZPhase_fidelity)(.5)) {
double ZZPhase_half = std::visit(
johnchildren marked this conversation as resolved.
Show resolved Hide resolved
overloaded{// A constant value.
[](double arg) { return arg; },
// A value depending on the input.
[](std::function<double(double)> arg) { return (arg)(.5); }},
*fid.ZZPhase_fidelity);
if (*fid.ZZMax_fidelity < ZZPhase_half) {
throw std::domain_error(
"The ZZMax fidelity cannot be smaller than the ZZPhase(0.5) "
"fidelity");
Expand Down
1 change: 1 addition & 0 deletions tket/test/src/test_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,7 @@ SCENARIO("Test compiler pass serializations") {
COMPPASSJSONTEST(KAKDecomposition, KAKDecomposition(OpType::CX, 0.98))
COMPPASSJSONTEST(
DecomposeTK2, DecomposeTK2({0.98, std::nullopt, std::nullopt}, false))
COMPPASSJSONTEST(DecomposeTK2, DecomposeTK2({0.98, 0.98, 0.98}))
COMPPASSJSONTEST(ThreeQubitSquash, ThreeQubitSquash(false))
COMPPASSJSONTEST(
EulerAngleReduction, gen_euler_pass(OpType::Rx, OpType::Ry, false))
Expand Down
Loading