diff --git a/pytket/conanfile.py b/pytket/conanfile.py index d53148a268..7b41667aee 100644 --- a/pytket/conanfile.py +++ b/pytket/conanfile.py @@ -32,7 +32,7 @@ def package(self): cmake.install() def requirements(self): - self.requires("tket/1.3.17@tket/stable") + self.requires("tket/1.3.18@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") diff --git a/pytket/docs/changelog.rst b/pytket/docs/changelog.rst index 7cad146fb9..cbdbbd58a7 100644 --- a/pytket/docs/changelog.rst +++ b/pytket/docs/changelog.rst @@ -1,6 +1,12 @@ Changelog ========= +Unreleased +---------- + +* Fix symbol substitution for classical operations. + + 1.31.1 (August 2024) -------------------- diff --git a/pytket/tests/classical_test.py b/pytket/tests/classical_test.py index 8d5ed1fd4d..c93fcce5ac 100644 --- a/pytket/tests/classical_test.py +++ b/pytket/tests/classical_test.py @@ -72,6 +72,8 @@ from pytket.passes import DecomposeClassicalExp, FlattenRegisters +from sympy import Symbol + from strategies import reg_name_regex, binary_digits, uint32, uint64 # type: ignore curr_file_path = Path(__file__).resolve().parent @@ -1481,5 +1483,14 @@ def test_box_equality_check() -> None: assert ceb1 == ClassicalExpBox(2, 0, 1, exp1) +def test_sym_sub_range_pred() -> None: + c = Circuit(1, 2) + c.H(0, condition=reg_eq(BitRegister("c", 2), 3)) + c1 = c.copy() + c.symbol_substitution({Symbol("a"): 0.5}) + + assert c == c1 + + if __name__ == "__main__": test_wasm() diff --git a/tket/conanfile.py b/tket/conanfile.py index 7c4ed09f49..677220d90e 100644 --- a/tket/conanfile.py +++ b/tket/conanfile.py @@ -23,7 +23,7 @@ class TketConan(ConanFile): name = "tket" - version = "1.3.17" + version = "1.3.18" package_type = "library" license = "Apache 2" homepage = "https://github.com/CQCL/tket" diff --git a/tket/include/tket/Ops/ClassicalOps.hpp b/tket/include/tket/Ops/ClassicalOps.hpp index cdb39bcf7e..af92c8332e 100644 --- a/tket/include/tket/Ops/ClassicalOps.hpp +++ b/tket/include/tket/Ops/ClassicalOps.hpp @@ -22,6 +22,7 @@ #include #include "Op.hpp" +#include "OpPtr.hpp" #include "tket/Utils/Json.hpp" namespace tket { @@ -47,11 +48,6 @@ class ClassicalOp : public Op { OpType type, unsigned n_i, unsigned n_io, unsigned n_o, const std::string &name = ""); - // Trivial overrides - Op_ptr symbol_substitution( - const SymEngine::map_basic_basic &) const override { - return std::make_shared(*this); - } SymSet free_symbols() const override { return {}; } unsigned n_qubits() const override { return 0; } @@ -141,6 +137,11 @@ class ClassicalTransformOp : public ClassicalEvalOp { unsigned n, const std::vector &values, const std::string &name = "ClassicalTransform"); + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + std::vector eval(const std::vector &x) const override; std::vector get_values() const { return values_; } @@ -171,6 +172,11 @@ class WASMOp : public ClassicalOp { std::vector _width_o_parameter, const std::string &_func_name, const std::string &_wasm_uid); + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + /** * return if the op is external */ @@ -284,6 +290,11 @@ class SetBitsOp : public ClassicalEvalOp { : ClassicalEvalOp(OpType::SetBits, 0, 0, values.size(), "SetBits"), values_(values) {} + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + std::string get_name(bool latex) const override; std::vector get_values() const { return values_; } @@ -304,6 +315,11 @@ class CopyBitsOp : public ClassicalEvalOp { explicit CopyBitsOp(unsigned n) : ClassicalEvalOp(OpType::CopyBits, n, 0, n, "CopyBits") {} + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + std::vector eval(const std::vector &x) const override; }; @@ -345,6 +361,11 @@ class RangePredicateOp : public PredicateOp { uint64_t b = std::numeric_limits::max()) : PredicateOp(OpType::RangePredicate, n, "RangePredicate"), a(a), b(b) {} + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + std::string get_name(bool latex) const override; uint64_t upper() const { return b; } @@ -384,6 +405,11 @@ class ExplicitPredicateOp : public PredicateOp { unsigned n, const std::vector &values, const std::string &name = "ExplicitPredicate"); + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + std::vector eval(const std::vector &x) const override; std::vector get_values() const { return values_; } @@ -430,6 +456,11 @@ class ExplicitModifierOp : public ModifyingOp { unsigned n, const std::vector &values, const std::string &name = "ExplicitModifier"); + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + std::vector eval(const std::vector &x) const override; std::vector get_values() const { return values_; } @@ -448,6 +479,11 @@ class MultiBitOp : public ClassicalEvalOp { public: MultiBitOp(std::shared_ptr op, unsigned n); + Op_ptr symbol_substitution( + const SymEngine::map_basic_basic &) const override { + return std::make_shared(*this); + } + std::string get_name(bool latex) const override; std::shared_ptr get_op() const { return op_; } diff --git a/tket/test/src/Circuit/test_Symbolic.cpp b/tket/test/src/Circuit/test_Symbolic.cpp index 2389786d6e..2445ed219e 100644 --- a/tket/test/src/Circuit/test_Symbolic.cpp +++ b/tket/test/src/Circuit/test_Symbolic.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -259,5 +260,28 @@ SCENARIO("Symbolic GPI, GPI2, AAMS") { } } +SCENARIO("Symbolic substitution for classical operations") { + std::vector and_table = {0, 1, 2, 7, 0, 1, 2, 7}; + std::shared_ptr and_ttop = + std::make_shared(3, and_table); + std::shared_ptr rpop = + std::make_shared(3, 2, 6); + Circuit circ(1, 4); + circ.add_op(OpType::H, {0}); + circ.add_op(and_ttop, {0, 1, 2}); + circ.add_op(and_ttop, {1, 2, 3}); + circ.add_op(rpop, {0, 1, 2, 3}); + circ.add_op(AndOp(), {2, 3, 0}); + circ.add_op(OrOp(), {0, 1, 2}); + circ.add_op(NotOp(), {2, 3}); + circ.add_op(ClassicalX(), {1}); + circ.add_op(ClassicalCX(), {0, 1}); + circ.add_op(AndWithOp(), {2, 3}); + Circuit circ1(circ); + symbol_map_t symmap; + circ1.symbol_substitution(symmap); + REQUIRE(circ == circ1); +} + } // namespace test_Symbolic } // namespace tket