use crate::circuit::gate::{StandardGate, gate_matrix};
use crate::circuit::{CircuitError, Parameter};
use alloc::borrow::Cow;
use ndarray::Array2;
use num_complex::Complex;
use smallvec::SmallVec;
use std::fmt;
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd, Debug, Clone)]
pub struct MCGate {
num_controls: u8,
gate: StandardGate,
}
impl MCGate {
pub fn new(num_controls: u8, gate: StandardGate) -> Self {
Self { num_controls, gate }
}
pub fn matrix(&self, params: &[f64]) -> Result<Cow<'_, Array2<Complex<f64>>>, CircuitError> {
let base_matrix = self.gate.matrix(params)?;
if self.num_controls == 0 {
return Ok(base_matrix);
}
let controlled = gate_matrix::control_matrix(&base_matrix, self.num_controls as usize);
Ok(Cow::Owned(controlled))
}
pub fn inverse(&self, params: &[Parameter]) -> Option<(MCGate, SmallVec<[Parameter; 3]>)> {
let (inv_gate, inv_params) = self.gate.inverse(params)?;
Some((
Self {
num_controls: self.num_controls,
gate: inv_gate,
},
inv_params,
))
}
pub fn num_ctrl_qubits(&self) -> usize {
self.num_controls as usize + self.gate.num_ctrl_qubits()
}
pub fn num_qubits(&self) -> usize {
self.num_controls as usize + self.gate.num_qubits()
}
pub fn num_params(&self) -> usize {
self.gate.num_params()
}
pub fn base_gate(&self) -> &StandardGate {
&self.gate
}
pub fn name(&self) -> String {
if self.num_controls == 0 {
self.gate.name().to_string()
} else {
format!("C{}-{}", self.num_controls, self.gate.name())
}
}
}
impl fmt::Display for MCGate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.name())
}
}