Skip to content

Commit

Permalink
Added z basis transformation to circuit_parser. (tensorflow#162)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Broughton <[email protected]>
  • Loading branch information
MichaelBroughton and MichaelBroughton authored Mar 17, 2020
1 parent 7ab25b1 commit 4fbd426
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 1 deletion.
41 changes: 41 additions & 0 deletions tensorflow_quantum/core/src/circuit_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,45 @@ Status CircuitFromPauliTerm(const tfq::proto::PauliTerm& term,
return CircuitFromProgram(measurement_program, num_qubits, circuit);
}

Status ZBasisCircuitFromPauliTerm(const tfq::proto::PauliTerm& term,
const int num_qubits, Circuit* circuit) {
Program measurement_program;
measurement_program.mutable_circuit()->set_scheduling_strategy(
cirq::google::api::v2::Circuit::MOMENT_BY_MOMENT);
Moment* term_moment = measurement_program.mutable_circuit()->add_moments();
float transform_exponent = 0.0;
std::string gate_type;
for (const tfq::proto::PauliQubitPair& pair : term.paulis()) {
if (pair.pauli_type() == "Z") {
// Z requires no transform.
continue;
}

// Assume it is X and the transform is Y^-0.5
transform_exponent = -0.5;
gate_type = "Y";
if (pair.pauli_type() == "Y") {
// Y regquires X**0.5 transform.
transform_exponent = 0.5;
gate_type = "X";
}

Operation* new_op = term_moment->add_operations();

// create corresponding eigen gate op.
new_op->add_qubits()->set_id(pair.qubit_id());
new_op->mutable_gate()->set_id(gate_type + "P");
(*new_op->mutable_args())["exponent"].mutable_arg_value()->set_float_value(
transform_exponent);
(*new_op->mutable_args())["global_shift"]
.mutable_arg_value()
->set_float_value(0.0);
(*new_op->mutable_args())["exponent_scalar"]
.mutable_arg_value()
->set_float_value(1.0);
}

return CircuitFromProgram(measurement_program, num_qubits, circuit);
}

} // namespace tfq
7 changes: 6 additions & 1 deletion tensorflow_quantum/core/src/circuit_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@ tensorflow::Status CircuitFromProgram(
const cirq::google::api::v2::Program& program, const int num_qubits,
Circuit* circuit);

// build the circuit taking the computational basis to the measurement basis
// build the circuit representing the pauli operations.
tensorflow::Status CircuitFromPauliTerm(const tfq::proto::PauliTerm& term,
const int num_qubits, Circuit* circuit);

// build the circuit taking pauliterms to z basis.
tensorflow::Status ZBasisCircuitFromPauliTerm(const tfq::proto::PauliTerm& term,
const int num_qubits,
Circuit* circuit);

} // namespace tfq

#endif // TFQ_CORE_SRC_CIRCUIT_PARSER_H_
149 changes: 149 additions & 0 deletions tensorflow_quantum/core/src/circuit_parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -238,5 +238,154 @@ TEST(CircuitParserTest, CircuitFromPauliTermPauli) {
ASSERT_EQ(test_circuit, real_circuit);
}

TEST(CircuitParserTest, ZBasisFromPauliTermX) {
tfq::proto::PauliTerm pauli_proto;
// The created circuit should not depend on the coefficient
pauli_proto.set_coefficient_real(3.14);
tfq::proto::PauliQubitPair* pair_proto = pauli_proto.add_paulis();
pair_proto->set_qubit_id("0");
pair_proto->set_pauli_type("X");

// Build the corresponding correct circuit
Circuit real_circuit;
YPowGateBuilder builder;
Gate gate_y;
::tensorflow::Status status;

real_circuit.num_qubits = 1;
absl::flat_hash_map<std::string, float> arg_map;
arg_map["global_shift"] = 0.0;
arg_map["exponent"] = -0.5;
arg_map["exponent_scalar"] = 1.0;
status = builder.Build(0, {0}, arg_map, &gate_y);
ASSERT_EQ(status, tensorflow::Status::OK());
real_circuit.gates.push_back(gate_y);

// Check conversion
Circuit test_circuit;
status = ZBasisCircuitFromPauliTerm(pauli_proto, 1, &test_circuit);
ASSERT_EQ(status, tensorflow::Status::OK());
ASSERT_EQ(test_circuit, real_circuit);
}

TEST(CircuitParserTest, ZBasisFromPauliTermY) {
tfq::proto::PauliTerm pauli_proto;
// The created circuit should not depend on the coefficient
pauli_proto.set_coefficient_real(3.14);
tfq::proto::PauliQubitPair* pair_proto = pauli_proto.add_paulis();
pair_proto->set_qubit_id("0");
pair_proto->set_pauli_type("Y");

// Build the corresponding correct circuit
Circuit real_circuit;
XPowGateBuilder builder;
Gate gate_x;
::tensorflow::Status status;

real_circuit.num_qubits = 1;
absl::flat_hash_map<std::string, float> arg_map;
arg_map["global_shift"] = 0.0;
arg_map["exponent"] = 0.5;
arg_map["exponent_scalar"] = 1.0;
status = builder.Build(0, {0}, arg_map, &gate_x);
ASSERT_EQ(status, tensorflow::Status::OK());
real_circuit.gates.push_back(gate_x);

// Check conversion
Circuit test_circuit;
status = ZBasisCircuitFromPauliTerm(pauli_proto, 1, &test_circuit);
ASSERT_EQ(status, tensorflow::Status::OK());
ASSERT_EQ(test_circuit, real_circuit);
}

TEST(CircuitParserTest, ZBasisFromPauliTermZ) {
tfq::proto::PauliTerm pauli_proto;
// The created circuit should not depend on the coefficient
pauli_proto.set_coefficient_real(3.14);
tfq::proto::PauliQubitPair* pair_proto = pauli_proto.add_paulis();
pair_proto->set_qubit_id("0");
pair_proto->set_pauli_type("Z");

// Build the corresponding correct circuit
Circuit empty_circuit;
empty_circuit.num_qubits = 1;
::tensorflow::Status status;

// Check conversion
Circuit test_circuit;
status = ZBasisCircuitFromPauliTerm(pauli_proto, 1, &test_circuit);
ASSERT_EQ(status, tensorflow::Status::OK());
ASSERT_EQ(test_circuit, empty_circuit);
}

TEST(CircuitParserTest, ZBasisFromPauliTermMulti) {
tfq::proto::PauliTerm pauli_proto;
// The created circuit should not depend on the coefficient
pauli_proto.set_coefficient_real(3.14);
tfq::proto::PauliQubitPair* pair_proto = pauli_proto.add_paulis();
pair_proto->set_qubit_id("0");
pair_proto->set_pauli_type("X");
pair_proto = pauli_proto.add_paulis();
pair_proto->set_qubit_id("1");
pair_proto->set_pauli_type("Z");
pair_proto = pauli_proto.add_paulis();
pair_proto->set_qubit_id("2");
pair_proto->set_pauli_type("X");
pair_proto = pauli_proto.add_paulis();
pair_proto->set_qubit_id("3");
pair_proto->set_pauli_type("Y");

// Build the corresponding correct circuit
Circuit real_circuit;
XPowGateBuilder x_builder;
YPowGateBuilder y_builder;
I2GateBuilder i_builder;
Gate gate;
::tensorflow::Status status;

real_circuit.num_qubits = 4;

// X -> Y**-0.5
absl::flat_hash_map<std::string, float> arg_map;
arg_map["global_shift"] = 0.0;
arg_map["exponent"] = -0.5;
arg_map["exponent_scalar"] = 1.0;
status = y_builder.Build(0, {3}, arg_map, &gate);
ASSERT_EQ(status, tensorflow::Status::OK());
real_circuit.gates.push_back(gate);

// Z -> nothing

// X -> Y**-0.5
arg_map["global_shift"] = 0.0;
arg_map["exponent"] = -0.5;
arg_map["exponent_scalar"] = 1.0;
status = y_builder.Build(0, {1}, arg_map, &gate);
ASSERT_EQ(status, tensorflow::Status::OK());
real_circuit.gates.push_back(gate);

// Y -> X^0.5
arg_map["global_shift"] = 0.0;
arg_map["exponent"] = 0.5;
arg_map["exponent_scalar"] = 1.0;
status = x_builder.Build(0, {0}, arg_map, &gate);
ASSERT_EQ(status, tensorflow::Status::OK());
real_circuit.gates.push_back(gate);

// Identity padding for orphan gates added here.
status = i_builder.Build(1, {0, 1}, {}, &gate);
ASSERT_EQ(status, tensorflow::Status::OK());
real_circuit.gates.push_back(gate);
status = i_builder.Build(1, {2, 3}, {}, &gate);
ASSERT_EQ(status, tensorflow::Status::OK());
real_circuit.gates.push_back(gate);

// Check conversion
Circuit test_circuit;
status = ZBasisCircuitFromPauliTerm(pauli_proto, 4, &test_circuit);
ASSERT_EQ(status, tensorflow::Status::OK());
ASSERT_EQ(test_circuit, real_circuit);
}

} // namespace
} // namespace tfq

0 comments on commit 4fbd426

Please sign in to comment.