in tensorflow_quantum/core/src/adj_util.cc [37:173]
void CreateGradientCircuit(
const QsimCircuit& circuit, const std::vector<GateMetaData>& metadata,
std::vector<std::vector<qsim::GateFused<QsimGate>>>* partial_fuses,
std::vector<GradientOfGate>* grad_gates) {
for (int i = 0; i < metadata.size(); i++) {
if (metadata[i].symbol_values.empty()) {
continue;
}
// found a gate that was constructed with symbols.
GradientOfGate grad;
// Single qubit Eigen.
if (circuit.gates[i].kind == qsim::Cirq::GateKind::kXPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kYPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kZPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kHPowGate) {
PopulateGradientSingleEigen(
metadata[i].create_f1, metadata[i].symbol_values[0], i,
circuit.gates[i].qubits[0], metadata[i].gate_params[0],
metadata[i].gate_params[1], metadata[i].gate_params[2], &grad);
grad_gates->push_back(grad);
}
// Two qubit Eigen.
else if (circuit.gates[i].kind == qsim::Cirq::GateKind::kCZPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kCXPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kXXPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kYYPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kZZPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kISwapPowGate ||
circuit.gates[i].kind == qsim::Cirq::GateKind::kSwapPowGate) {
bool swapq = circuit.gates[i].swapped;
PopulateGradientTwoEigen(
metadata[i].create_f2, metadata[i].symbol_values[0], i,
swapq ? circuit.gates[i].qubits[1] : circuit.gates[i].qubits[0],
swapq ? circuit.gates[i].qubits[0] : circuit.gates[i].qubits[1],
metadata[i].gate_params[0], metadata[i].gate_params[1],
metadata[i].gate_params[2], &grad);
grad_gates->push_back(grad);
}
// PhasedX
else if (circuit.gates[i].kind == qsim::Cirq::GateKind::kPhasedXPowGate) {
// Process potentially several symbols.
for (int j = 0; j < metadata[i].symbol_values.size(); j++) {
if (metadata[i].placeholder_names[j] ==
GateParamNames::kPhaseExponent) {
PopulateGradientPhasedXPhasedExponent(
metadata[i].symbol_values[j], i, circuit.gates[i].qubits[0],
metadata[i].gate_params[0], metadata[i].gate_params[1],
metadata[i].gate_params[2], metadata[i].gate_params[3],
metadata[i].gate_params[4], &grad);
} else if (metadata[i].placeholder_names[j] ==
GateParamNames::kExponent) {
PopulateGradientPhasedXExponent(
metadata[i].symbol_values[j], i, circuit.gates[i].qubits[0],
metadata[i].gate_params[0], metadata[i].gate_params[1],
metadata[i].gate_params[2], metadata[i].gate_params[3],
metadata[i].gate_params[4], &grad);
}
}
grad_gates->push_back(grad);
}
// Fsim
else if (circuit.gates[i].kind == qsim::Cirq::GateKind::kFSimGate) {
// Process potentially several symbols.
bool swapq = circuit.gates[i].swapped;
for (int j = 0; j < metadata[i].symbol_values.size(); j++) {
if (metadata[i].placeholder_names[j] == GateParamNames::kTheta) {
PopulateGradientFsimTheta(
metadata[i].symbol_values[j], i,
swapq ? circuit.gates[i].qubits[1] : circuit.gates[i].qubits[0],
swapq ? circuit.gates[i].qubits[0] : circuit.gates[i].qubits[1],
metadata[i].gate_params[0], metadata[i].gate_params[1],
metadata[i].gate_params[2], metadata[i].gate_params[3], &grad);
} else if (metadata[i].placeholder_names[j] == GateParamNames::kPhi) {
PopulateGradientFsimPhi(
metadata[i].symbol_values[j], i,
swapq ? circuit.gates[i].qubits[1] : circuit.gates[i].qubits[0],
swapq ? circuit.gates[i].qubits[0] : circuit.gates[i].qubits[1],
metadata[i].gate_params[0], metadata[i].gate_params[1],
metadata[i].gate_params[2], metadata[i].gate_params[3], &grad);
}
}
grad_gates->push_back(grad);
}
// PhasedISwap
else if (circuit.gates[i].kind ==
qsim::Cirq::GateKind::kPhasedISwapPowGate) {
// Process potentially several symbols.
bool swapq = circuit.gates[i].swapped;
for (int j = 0; j < metadata[i].symbol_values.size(); j++) {
if (metadata[i].placeholder_names[j] ==
GateParamNames::kPhaseExponent) {
PopulateGradientPhasedISwapPhasedExponent(
metadata[i].symbol_values[j], i,
swapq ? circuit.gates[i].qubits[1] : circuit.gates[i].qubits[0],
swapq ? circuit.gates[i].qubits[0] : circuit.gates[i].qubits[1],
metadata[i].gate_params[0], metadata[i].gate_params[1],
metadata[i].gate_params[2], metadata[i].gate_params[3], &grad);
} else if (metadata[i].placeholder_names[j] ==
GateParamNames::kExponent) {
PopulateGradientPhasedISwapExponent(
metadata[i].symbol_values[j], i,
swapq ? circuit.gates[i].qubits[1] : circuit.gates[i].qubits[0],
swapq ? circuit.gates[i].qubits[0] : circuit.gates[i].qubits[1],
metadata[i].gate_params[0], metadata[i].gate_params[1],
metadata[i].gate_params[2], metadata[i].gate_params[3], &grad);
}
}
grad_gates->push_back(grad);
}
}
// Produce partial fuses around the gradient gates.
auto fuser = qsim::BasicGateFuser<qsim::IO, QsimGate>();
auto left = circuit.gates.begin();
auto right = left;
partial_fuses->assign(grad_gates->size() + 1,
std::vector<qsim::GateFused<QsimGate>>({}));
for (int i = 0; i < grad_gates->size(); i++) {
right = circuit.gates.begin() + (*grad_gates)[i].index;
(*partial_fuses)[i] =
fuser.FuseGates(qsim::BasicGateFuser<qsim::IO, QsimGate>::Parameter(),
circuit.num_qubits, left, right);
left = right + 1;
}
right = circuit.gates.end();
(*partial_fuses)[grad_gates->size()] =
fuser.FuseGates(qsim::BasicGateFuser<qsim::IO, QsimGate>::Parameter(),
circuit.num_qubits, left, right);
}