From 22d1a056e538b649b89375e844f5e17e4b732120 Mon Sep 17 00:00:00 2001 From: Michael Broughton Date: Mon, 29 Mar 2021 15:06:51 -0700 Subject: [PATCH 1/2] Added BF channel support. --- .../core/serialize/serializer.py | 35 ++++++++++++++++++ .../core/serialize/serializer_test.py | 6 +++- .../core/src/circuit_parser_qsim.cc | 22 +++++++++++- .../core/src/circuit_parser_qsim_test.cc | 36 +++++++++++++++++++ tensorflow_quantum/python/util.py | 10 +++++- 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/tensorflow_quantum/core/serialize/serializer.py b/tensorflow_quantum/core/serialize/serializer.py index 966ee9b5f..4992797ee 100644 --- a/tensorflow_quantum/core/serialize/serializer.py +++ b/tensorflow_quantum/core/serialize/serializer.py @@ -231,6 +231,39 @@ def _depolarize_channel_deserializer(): args=args) +def _bit_flip_channel_serializer(): + """Make standard serializer for BitFlip channel.""" + + args = [ + # cirq channels can't contain symbols. + cirq.google.SerializingArg(serialized_name="p", + serialized_type=float, + op_getter=lambda x: x.gate.p), + cirq.google.SerializingArg(serialized_name="control_qubits", + serialized_type=str, + op_getter=lambda x: ''), + cirq.google.SerializingArg(serialized_name="control_values", + serialized_type=str, + op_getter=lambda x: '') + ] + return cirq.google.GateOpSerializer(gate_type=cirq.BitFlipChannel, + serialized_gate_id="BF", + args=args, + can_serialize_predicate=_CONSTANT_TRUE) + + +def _bit_flip_channel_deserializer(): + """Make standard deserializer for depolarization channel.""" + + args = [ + cirq.google.DeserializingArg(serialized_name="p", + constructor_arg_name="p") + ] + return cirq.google.GateOpDeserializer(serialized_gate_id="BF", + gate_constructor=cirq.BitFlipChannel, + args=args) + + def _eigen_gate_serializer(gate_type, serialized_id): """Make standard serializer for eigen gates.""" @@ -530,6 +563,7 @@ def _scalar_combiner(exponent, global_shift, exponent_scalar, for g, g_name in PHASED_EIGEN_GATES_DICT.items() ] + [ _asymmetric_depolarize_serializer(), + _bit_flip_channel_serializer(), _depolarize_channel_serializer(), _fsim_gate_serializer(), _identity_gate_serializer() @@ -543,6 +577,7 @@ def _scalar_combiner(exponent, global_shift, exponent_scalar, for g, g_name in PHASED_EIGEN_GATES_DICT.items() ] + [ _asymmetric_depolarize_deserializer(), + _bit_flip_channel_deserializer(), _depolarize_channel_deserializer(), _fsim_gate_deserializer(), _identity_gate_deserializer() diff --git a/tensorflow_quantum/core/serialize/serializer_test.py b/tensorflow_quantum/core/serialize/serializer_test.py index 54961a6c1..dc1451524 100644 --- a/tensorflow_quantum/core/serialize/serializer_test.py +++ b/tensorflow_quantum/core/serialize/serializer_test.py @@ -413,7 +413,11 @@ def _get_noise_proto_pairs(): (cirq.Circuit( cirq.asymmetric_depolarize(p_x=0.1, p_y=0.2, p_z=0.3)(q0)), _build_op_proto("ADP", ['p_x', 'p_y', 'p_z'], [0.1, 0.2, 0.3], - ['0_0'])) + ['0_0'])), + + # Bit flip. + (cirq.Circuit(cirq.bit_flip(p=0.1)(q0)), + _build_op_proto("BF", ['p'], [0.1], ['0_0'])), ] return pairs diff --git a/tensorflow_quantum/core/src/circuit_parser_qsim.cc b/tensorflow_quantum/core/src/circuit_parser_qsim.cc index 051d1d878..b205ddbb3 100644 --- a/tensorflow_quantum/core/src/circuit_parser_qsim.cc +++ b/tensorflow_quantum/core/src/circuit_parser_qsim.cc @@ -641,6 +641,25 @@ inline Status DepolarizingChannel(const Operation& op, return Status::OK(); } +inline Status BitFlipChannel(const Operation& op, const unsigned int num_qubits, + const unsigned int time, + NoisyQsimCircuit* ncircuit) { + int q; + bool unused; + float p; + Status u; + unused = absl::SimpleAtoi(op.qubits(0).id(), &q); + + u = ParseProtoArg(op, "p", {}, &p); + if (!u.ok()) { + return u; + } + auto chan = + qsim::Cirq::BitFlipChannel::Create(time, num_qubits - q - 1, p); + ncircuit->channels.push_back(chan); + return Status::OK(); +} + tensorflow::Status ParseAppendChannel(const Operation& op, const unsigned int num_qubits, const unsigned int time, @@ -650,7 +669,8 @@ tensorflow::Status ParseAppendChannel(const Operation& op, std::string, std::function> chan_func_map = {{"DP", &DepolarizingChannel}, - {"ADP", &AsymmetricDepolarizingChannel}}; + {"ADP", &AsymmetricDepolarizingChannel}, + {"BF", &BitFlipChannel}}; auto build_f = chan_func_map.find(op.gate().id()); if (build_f == chan_func_map.end()) { diff --git a/tensorflow_quantum/core/src/circuit_parser_qsim_test.cc b/tensorflow_quantum/core/src/circuit_parser_qsim_test.cc index 3ea4a0019..48ffdddf6 100644 --- a/tensorflow_quantum/core/src/circuit_parser_qsim_test.cc +++ b/tensorflow_quantum/core/src/circuit_parser_qsim_test.cc @@ -1312,6 +1312,42 @@ TEST(QsimCircuitParserTest, Depolarizing) { ASSERT_EQ(test_circuit.num_qubits, 1); } +TEST(QsimCircuitParserTest, BitFlip) { + float p = 0.1234; + auto reference = qsim::Cirq::BitFlipChannel::Create(0, 0, p); + Program program_proto; + Circuit* circuit_proto = program_proto.mutable_circuit(); + circuit_proto->set_scheduling_strategy(circuit_proto->MOMENT_BY_MOMENT); + Moment* moments_proto = circuit_proto->add_moments(); + + // Add channel. + Operation* operations_proto = moments_proto->add_operations(); + Gate* gate_proto = operations_proto->mutable_gate(); + gate_proto->set_id("BF"); + + // Set the args. + google::protobuf::Map* args_proto = + operations_proto->mutable_args(); + (*args_proto)["p"] = MakeArg(p); + + // Set the control args. + (*args_proto)["control_qubits"] = MakeControlArg(""); + (*args_proto)["control_values"] = MakeControlArg(""); + + // Set the qubits. + Qubit* qubits_proto = operations_proto->add_qubits(); + qubits_proto->set_id("0"); + + NoisyQsimCircuit test_circuit; + + ASSERT_EQ( + NoisyQsimCircuitFromProgram(program_proto, {}, 1, false, &test_circuit), + tensorflow::Status::OK()); + AssertChannelEqual(test_circuit.channels[0], reference); + ASSERT_EQ(test_circuit.channels.size(), 1); + ASSERT_EQ(test_circuit.num_qubits, 1); +} + TEST(QsimCircuitParserTest, NoisyEmpty) { Program program_proto; Circuit* circuit_proto = program_proto.mutable_circuit(); diff --git a/tensorflow_quantum/python/util.py b/tensorflow_quantum/python/util.py index 4ed47fc55..f6829c9ad 100644 --- a/tensorflow_quantum/python/util.py +++ b/tensorflow_quantum/python/util.py @@ -28,7 +28,9 @@ # Can't use set() since channels don't give proper support. _SUPPORTED_CHANNELS = [ - cirq.DepolarizingChannel, cirq.AsymmetricDepolarizingChannel + cirq.DepolarizingChannel, + cirq.AsymmetricDepolarizingChannel, + cirq.BitFlipChannel, ] @@ -73,6 +75,7 @@ def get_supported_channels(): channel_mapping = dict() channel_mapping[cirq.DepolarizingChannel(0.01)] = 1 channel_mapping[cirq.AsymmetricDepolarizingChannel(0.01, 0.02, 0.03)] = 1 + channel_mapping[cirq.BitFlipChannel(0.01)] = 1 return channel_mapping @@ -492,6 +495,11 @@ def _expression_approx_eq(exp_1, exp_2, atol): # TODO: replace with cirq.approx_eq once # https://github.com/quantumlib/Cirq/issues/3886 is resolved for all channels. def _channel_approx_eq(op_true, op_deser, atol=1e-5): + + if isinstance(op_true, cirq.BitFlipChannel): + if isinstance(op_deser, cirq.BitFlipChannel): + return abs(op_true.p - op_deser.p) < atol + if isinstance(op_true, cirq.DepolarizingChannel): if isinstance(op_deser, cirq.DepolarizingChannel): return abs(op_true.p - op_deser.p) < atol From 63522dfb11c05f68cd6631dcb486f4e9af0ec599 Mon Sep 17 00:00:00 2001 From: Michael Broughton Date: Mon, 29 Mar 2021 15:08:32 -0700 Subject: [PATCH 2/2] typo fix. --- tensorflow_quantum/core/serialize/serializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow_quantum/core/serialize/serializer.py b/tensorflow_quantum/core/serialize/serializer.py index 4992797ee..fc214bd2b 100644 --- a/tensorflow_quantum/core/serialize/serializer.py +++ b/tensorflow_quantum/core/serialize/serializer.py @@ -253,7 +253,7 @@ def _bit_flip_channel_serializer(): def _bit_flip_channel_deserializer(): - """Make standard deserializer for depolarization channel.""" + """Make standard deserializer for BitFlip channel.""" args = [ cirq.google.DeserializingArg(serialized_name="p",