Skip to content

Commit 6e67c0e

Browse files
Added PF channel support. (#528)
* Added PF channel support. * conflict fixup.
1 parent 49a5b2a commit 6e67c0e

File tree

5 files changed

+106
-4
lines changed

5 files changed

+106
-4
lines changed

tensorflow_quantum/core/serialize/serializer.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,39 @@ def _phase_damp_channel_deserializer():
365365
args=args)
366366

367367

368+
def _phase_flip_channel_serializer():
369+
"""Make standard serializer for PhaseFlip channel."""
370+
args = [
371+
# cirq channels can't contain symbols.
372+
cirq.google.SerializingArg(serialized_name="p",
373+
serialized_type=float,
374+
op_getter=lambda x: x.gate.p),
375+
cirq.google.SerializingArg(serialized_name="control_qubits",
376+
serialized_type=str,
377+
op_getter=lambda x: ''),
378+
cirq.google.SerializingArg(serialized_name="control_values",
379+
serialized_type=str,
380+
op_getter=lambda x: '')
381+
]
382+
return cirq.google.GateOpSerializer(gate_type=cirq.PhaseFlipChannel,
383+
serialized_gate_id="PF",
384+
args=args,
385+
can_serialize_predicate=_CONSTANT_TRUE)
386+
387+
388+
def _phase_flip_channel_deserializer():
389+
"""Make standard deserializer for PhaseFlip channel."""
390+
391+
args = [
392+
cirq.google.DeserializingArg(serialized_name="p",
393+
constructor_arg_name="p")
394+
]
395+
return cirq.google.GateOpDeserializer(
396+
serialized_gate_id="PF",
397+
gate_constructor=cirq.PhaseFlipChannel,
398+
args=args)
399+
400+
368401
# Gates.
369402
def _eigen_gate_serializer(gate_type, serialized_id):
370403
"""Make standard serializer for eigen gates."""
@@ -671,7 +704,8 @@ def _scalar_combiner(exponent, global_shift, exponent_scalar,
671704
_gad_channel_serializer(),
672705
_identity_gate_serializer(),
673706
_phase_damp_channel_serializer(),
674-
_reset_channel_serializer()
707+
_reset_channel_serializer(),
708+
_phase_flip_channel_serializer()
675709
]
676710

677711
DESERIALIZERS = [
@@ -688,7 +722,8 @@ def _scalar_combiner(exponent, global_shift, exponent_scalar,
688722
_gad_channel_deserializer(),
689723
_identity_gate_deserializer(),
690724
_phase_damp_channel_deserializer(),
691-
_reset_channel_deserializer()
725+
_reset_channel_deserializer(),
726+
_phase_flip_channel_deserializer()
692727
]
693728

694729
SERIALIZER = cirq.google.SerializableGateSet(gate_set_name="tfq_gate_set",

tensorflow_quantum/core/serialize/serializer_test.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,11 @@ def _get_noise_proto_pairs():
428428

429429
# Phase damp.
430430
(cirq.Circuit(cirq.phase_damp(gamma=0.1)(q0)),
431-
_build_op_proto("PD", ['gamma'], [0.1], ['0_0']))
431+
_build_op_proto("PD", ['gamma'], [0.1], ['0_0'])),
432+
433+
# Phase flip.
434+
(cirq.Circuit(cirq.phase_flip(p=0.1)(q0)),
435+
_build_op_proto("PF", ['p'], [0.1], ['0_0']))
432436
]
433437
return pairs
434438

tensorflow_quantum/core/src/circuit_parser_qsim.cc

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,27 @@ inline Status PhaseDampingChannel(const Operation& op,
717717
return Status::OK();
718718
}
719719

720+
inline Status PhaseFlipChannel(const Operation& op,
721+
const unsigned int num_qubits,
722+
const unsigned int time,
723+
NoisyQsimCircuit* ncircuit) {
724+
int q;
725+
bool unused;
726+
float p;
727+
Status u;
728+
unused = absl::SimpleAtoi(op.qubits(0).id(), &q);
729+
730+
u = ParseProtoArg(op, "p", {}, &p);
731+
if (!u.ok()) {
732+
return u;
733+
}
734+
735+
auto chan =
736+
qsim::Cirq::PhaseFlipChannel<float>::Create(time, num_qubits - q - 1, p);
737+
ncircuit->channels.push_back(chan);
738+
return Status::OK();
739+
}
740+
720741
tensorflow::Status ParseAppendChannel(const Operation& op,
721742
const unsigned int num_qubits,
722743
const unsigned int time,
@@ -729,7 +750,7 @@ tensorflow::Status ParseAppendChannel(const Operation& op,
729750
{"DP", &DepolarizingChannel}, {"ADP", &AsymmetricDepolarizingChannel},
730751
{"GAD", &GADChannel}, {"AD", &AmplitudeDampingChannel},
731752
{"RST", &ResetChannel}, {"PD", &PhaseDampingChannel},
732-
};
753+
{"PF", &PhaseFlipChannel}};
733754

734755
auto build_f = chan_func_map.find(op.gate().id());
735756
if (build_f == chan_func_map.end()) {

tensorflow_quantum/core/src/circuit_parser_qsim_test.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,42 @@ TEST(QsimCircuitParserTest, PhaseDamping) {
14591459
ASSERT_EQ(test_circuit.num_qubits, 1);
14601460
}
14611461

1462+
TEST(QsimCircuitParserTest, PhaseFlip) {
1463+
float p = 0.1234;
1464+
auto reference = qsim::Cirq::PhaseFlipChannel<float>::Create(0, 0, p);
1465+
Program program_proto;
1466+
Circuit* circuit_proto = program_proto.mutable_circuit();
1467+
circuit_proto->set_scheduling_strategy(circuit_proto->MOMENT_BY_MOMENT);
1468+
Moment* moments_proto = circuit_proto->add_moments();
1469+
1470+
// Add channel.
1471+
Operation* operations_proto = moments_proto->add_operations();
1472+
Gate* gate_proto = operations_proto->mutable_gate();
1473+
gate_proto->set_id("PF");
1474+
1475+
// Set the args.
1476+
google::protobuf::Map<std::string, Arg>* args_proto =
1477+
operations_proto->mutable_args();
1478+
(*args_proto)["p"] = MakeArg(p);
1479+
1480+
// Set the control args.
1481+
(*args_proto)["control_qubits"] = MakeControlArg("");
1482+
(*args_proto)["control_values"] = MakeControlArg("");
1483+
1484+
// Set the qubits.
1485+
Qubit* qubits_proto = operations_proto->add_qubits();
1486+
qubits_proto->set_id("0");
1487+
1488+
NoisyQsimCircuit test_circuit;
1489+
1490+
ASSERT_EQ(
1491+
NoisyQsimCircuitFromProgram(program_proto, {}, 1, false, &test_circuit),
1492+
tensorflow::Status::OK());
1493+
AssertChannelEqual(test_circuit.channels[0], reference);
1494+
ASSERT_EQ(test_circuit.channels.size(), 1);
1495+
ASSERT_EQ(test_circuit.num_qubits, 1);
1496+
}
1497+
14621498
TEST(QsimCircuitParserTest, NoisyEmpty) {
14631499
Program program_proto;
14641500
Circuit* circuit_proto = program_proto.mutable_circuit();

tensorflow_quantum/python/util.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
cirq.GeneralizedAmplitudeDampingChannel,
3535
cirq.ResetChannel,
3636
cirq.PhaseDampingChannel,
37+
cirq.PhaseFlipChannel,
3738
]
3839

3940

@@ -82,6 +83,7 @@ def get_supported_channels():
8283
channel_mapping[cirq.AmplitudeDampingChannel(0.01)] = 1
8384
channel_mapping[cirq.ResetChannel()] = 1
8485
channel_mapping[cirq.PhaseDampingChannel(0.01)] = 1
86+
channel_mapping[cirq.PhaseFlipChannel(0.01)] = 1
8587

8688
return channel_mapping
8789

@@ -528,6 +530,10 @@ def _channel_approx_eq(op_true, op_deser, atol=1e-5):
528530
if isinstance(op_deser, cirq.PhaseDampingChannel):
529531
return abs(op_true.gamma - op_deser.gamma) < atol
530532

533+
if isinstance(op_true, cirq.PhaseFlipChannel):
534+
if isinstance(op_deser, cirq.PhaseFlipChannel):
535+
return abs(op_true.p - op_deser.p) < atol
536+
531537
return False
532538

533539

0 commit comments

Comments
 (0)