use itertools::chain;
use num::Integer;
use crate::ir::gate::{DecomposedGate, QuantumGate};
use super::{
u2,
x::{c2to4x, CXMode},
};
pub fn network(
gate: QuantumGate,
control: &[usize],
aux_qubits: &[usize],
target: usize,
cx_mode: CXMode,
approximated: bool,
) -> Vec<DecomposedGate> {
let n = control.len();
let n_cx = match cx_mode {
CXMode::C2X => 2,
CXMode::C3X => 3,
};
if matches!(gate, QuantumGate::PauliX) && n <= n_cx {
return c2to4x::c1to4x(control, target, approximated);
} else if n == 1 {
return u2::cu2(gate.matrix(), control[0], target);
} else if n == 2 && matches!(cx_mode, CXMode::C3X) {
return chain!(
c2to4x::c1to4x(control, aux_qubits[0], true),
u2::cu2(gate.matrix(), aux_qubits[0], target),
c2to4x::c1to4x(control, aux_qubits[0], true)
)
.collect();
}
let (num_groups, rem) = n.div_rem(&n_cx);
let left_instructions = (0..num_groups)
.flat_map(|i| c2to4x::c1to4x(&control[n_cx * i..n_cx * i + n_cx], aux_qubits[i], true));
let new_ctrl = if rem != 0 {
&control[control.len() - rem..]
.iter()
.copied()
.chain(aux_qubits[..num_groups].iter().copied())
.collect::<Vec<_>>()
} else {
&aux_qubits[..num_groups]
};
left_instructions
.clone()
.chain(network(
gate,
new_ctrl,
&aux_qubits[num_groups..],
target,
cx_mode,
approximated,
))
.chain(left_instructions.rev().map(|gate| gate.inverse()))
.collect()
}