use super::{
gates::{TQRx, TQRy, TQRz, TQCNOT},
CType, TQDevice, TQModule, TQOperator, TQParameter,
};
use crate::error::{MLError, Result};
use scirs2_core::ndarray::{Array1, ArrayD};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EntanglementPattern {
Linear,
ReverseLinear,
Circular,
Full,
Custom(Vec<(usize, usize)>),
}
impl EntanglementPattern {
pub fn generate_pairs(&self, n_wires: usize) -> Vec<(usize, usize)> {
match self {
EntanglementPattern::Linear => {
(0..n_wires.saturating_sub(1)).map(|i| (i, i + 1)).collect()
}
EntanglementPattern::ReverseLinear => (1..n_wires).rev().map(|i| (i, i - 1)).collect(),
EntanglementPattern::Circular => {
let mut pairs: Vec<(usize, usize)> =
(0..n_wires.saturating_sub(1)).map(|i| (i, i + 1)).collect();
if n_wires > 2 {
pairs.push((n_wires - 1, 0));
}
pairs
}
EntanglementPattern::Full => {
let mut pairs = Vec::new();
for i in 0..n_wires {
for j in (i + 1)..n_wires {
pairs.push((i, j));
}
}
pairs
}
EntanglementPattern::Custom(pairs) => pairs.clone(),
}
}
}
pub struct RealAmplitudesLayer {
pub n_wires: usize,
pub reps: usize,
pub entanglement: EntanglementPattern,
ry_gates: Vec<Vec<TQRy>>,
pub final_rotation: bool,
static_mode: bool,
}
impl RealAmplitudesLayer {
pub fn new(n_wires: usize, reps: usize, entanglement: EntanglementPattern) -> Self {
let mut ry_gates = Vec::new();
for _ in 0..reps {
let layer: Vec<TQRy> = (0..n_wires).map(|_| TQRy::new(true, true)).collect();
ry_gates.push(layer);
}
let final_layer: Vec<TQRy> = (0..n_wires).map(|_| TQRy::new(true, true)).collect();
ry_gates.push(final_layer);
Self {
n_wires,
reps,
entanglement,
ry_gates,
final_rotation: true,
static_mode: false,
}
}
pub fn without_final_rotation(mut self) -> Self {
self.final_rotation = false;
self
}
}
impl TQModule for RealAmplitudesLayer {
fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
let entanglement_pairs = self.entanglement.generate_pairs(self.n_wires);
for rep in 0..self.reps {
for (wire, gate) in self.ry_gates[rep].iter_mut().enumerate() {
gate.apply(qdev, &[wire])?;
}
for (control, target) in &entanglement_pairs {
let mut cnot = TQCNOT::new();
cnot.apply(qdev, &[*control, *target])?;
}
}
if self.final_rotation && self.reps < self.ry_gates.len() {
for (wire, gate) in self.ry_gates[self.reps].iter_mut().enumerate() {
gate.apply(qdev, &[wire])?;
}
}
Ok(())
}
fn parameters(&self) -> Vec<TQParameter> {
let num_layers = if self.final_rotation {
self.reps + 1
} else {
self.reps
};
self.ry_gates[..num_layers]
.iter()
.flat_map(|layer| layer.iter().flat_map(|g| g.parameters()))
.collect()
}
fn n_wires(&self) -> Option<usize> {
Some(self.n_wires)
}
fn set_n_wires(&mut self, n_wires: usize) {
self.n_wires = n_wires;
}
fn is_static_mode(&self) -> bool {
self.static_mode
}
fn static_on(&mut self) {
self.static_mode = true;
}
fn static_off(&mut self) {
self.static_mode = false;
}
fn name(&self) -> &str {
"RealAmplitudesLayer"
}
}
pub struct EfficientSU2Layer {
pub n_wires: usize,
pub reps: usize,
pub entanglement: EntanglementPattern,
ry_gates: Vec<Vec<TQRy>>,
rz_gates: Vec<Vec<TQRz>>,
pub final_rotation: bool,
static_mode: bool,
}
impl EfficientSU2Layer {
pub fn new(n_wires: usize, reps: usize, entanglement: EntanglementPattern) -> Self {
let mut ry_gates = Vec::new();
let mut rz_gates = Vec::new();
for _ in 0..=reps {
let ry_layer: Vec<TQRy> = (0..n_wires).map(|_| TQRy::new(true, true)).collect();
ry_gates.push(ry_layer);
let rz_layer: Vec<TQRz> = (0..n_wires).map(|_| TQRz::new(true, true)).collect();
rz_gates.push(rz_layer);
}
Self {
n_wires,
reps,
entanglement,
ry_gates,
rz_gates,
final_rotation: true,
static_mode: false,
}
}
pub fn without_final_rotation(mut self) -> Self {
self.final_rotation = false;
self
}
}
impl TQModule for EfficientSU2Layer {
fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
let entanglement_pairs = self.entanglement.generate_pairs(self.n_wires);
for rep in 0..self.reps {
for (wire, gate) in self.ry_gates[rep].iter_mut().enumerate() {
gate.apply(qdev, &[wire])?;
}
for (wire, gate) in self.rz_gates[rep].iter_mut().enumerate() {
gate.apply(qdev, &[wire])?;
}
for (control, target) in &entanglement_pairs {
let mut cnot = TQCNOT::new();
cnot.apply(qdev, &[*control, *target])?;
}
}
if self.final_rotation {
for (wire, gate) in self.ry_gates[self.reps].iter_mut().enumerate() {
gate.apply(qdev, &[wire])?;
}
for (wire, gate) in self.rz_gates[self.reps].iter_mut().enumerate() {
gate.apply(qdev, &[wire])?;
}
}
Ok(())
}
fn parameters(&self) -> Vec<TQParameter> {
let num_layers = if self.final_rotation {
self.reps + 1
} else {
self.reps
};
let ry_params = self.ry_gates[..num_layers]
.iter()
.flat_map(|layer| layer.iter().flat_map(|g| g.parameters()));
let rz_params = self.rz_gates[..num_layers]
.iter()
.flat_map(|layer| layer.iter().flat_map(|g| g.parameters()));
ry_params.chain(rz_params).collect()
}
fn n_wires(&self) -> Option<usize> {
Some(self.n_wires)
}
fn set_n_wires(&mut self, n_wires: usize) {
self.n_wires = n_wires;
}
fn is_static_mode(&self) -> bool {
self.static_mode
}
fn static_on(&mut self) {
self.static_mode = true;
}
fn static_off(&mut self) {
self.static_mode = false;
}
fn name(&self) -> &str {
"EfficientSU2Layer"
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RotationType {
RX,
RY,
RZ,
}
pub struct TwoLocalLayer {
pub n_wires: usize,
pub reps: usize,
pub rotation_gates: Vec<RotationType>,
pub entanglement: EntanglementPattern,
parameters: Vec<TQParameter>,
static_mode: bool,
}
impl TwoLocalLayer {
pub fn new(
n_wires: usize,
reps: usize,
rotation_gates: Vec<RotationType>,
entanglement: EntanglementPattern,
) -> Self {
let params_per_rep = n_wires * rotation_gates.len();
let total_params = (reps + 1) * params_per_rep;
let parameters: Vec<TQParameter> = (0..total_params)
.map(|i| {
let param_data = ArrayD::zeros(scirs2_core::ndarray::IxDyn(&[1, 1]));
TQParameter::new(param_data, format!("param_{}", i))
})
.collect();
Self {
n_wires,
reps,
rotation_gates,
entanglement,
parameters,
static_mode: false,
}
}
}
impl TQModule for TwoLocalLayer {
fn forward(&mut self, qdev: &mut TQDevice) -> Result<()> {
let entanglement_pairs = self.entanglement.generate_pairs(self.n_wires);
let params_per_layer = self.n_wires * self.rotation_gates.len();
for rep in 0..=self.reps {
let param_offset = rep * params_per_layer;
for (rot_idx, rot_type) in self.rotation_gates.iter().enumerate() {
for wire in 0..self.n_wires {
let param_idx = param_offset + rot_idx * self.n_wires + wire;
let param_val = if self.parameters[param_idx].data.len() > 0 {
self.parameters[param_idx].data[[0, 0]]
} else {
0.0
};
match rot_type {
RotationType::RX => {
let mut gate = TQRx::new(true, true);
gate.apply_with_params(qdev, &[wire], Some(&[param_val]))?;
}
RotationType::RY => {
let mut gate = TQRy::new(true, true);
gate.apply_with_params(qdev, &[wire], Some(&[param_val]))?;
}
RotationType::RZ => {
let mut gate = TQRz::new(true, true);
gate.apply_with_params(qdev, &[wire], Some(&[param_val]))?;
}
}
}
}
if rep < self.reps {
for (control, target) in &entanglement_pairs {
let mut cnot = TQCNOT::new();
cnot.apply(qdev, &[*control, *target])?;
}
}
}
Ok(())
}
fn parameters(&self) -> Vec<TQParameter> {
self.parameters.clone()
}
fn n_wires(&self) -> Option<usize> {
Some(self.n_wires)
}
fn set_n_wires(&mut self, n_wires: usize) {
self.n_wires = n_wires;
}
fn is_static_mode(&self) -> bool {
self.static_mode
}
fn static_on(&mut self) {
self.static_mode = true;
}
fn static_off(&mut self) {
self.static_mode = false;
}
fn name(&self) -> &str {
"TwoLocalLayer"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_entanglement_linear() {
let pattern = EntanglementPattern::Linear;
let pairs = pattern.generate_pairs(4);
assert_eq!(pairs, vec![(0, 1), (1, 2), (2, 3)]);
}
#[test]
fn test_entanglement_circular() {
let pattern = EntanglementPattern::Circular;
let pairs = pattern.generate_pairs(4);
assert_eq!(pairs, vec![(0, 1), (1, 2), (2, 3), (3, 0)]);
}
#[test]
fn test_entanglement_full() {
let pattern = EntanglementPattern::Full;
let pairs = pattern.generate_pairs(3);
assert_eq!(pairs, vec![(0, 1), (0, 2), (1, 2)]);
}
#[test]
fn test_real_amplitudes_creation() {
let layer = RealAmplitudesLayer::new(4, 2, EntanglementPattern::Linear);
assert_eq!(layer.n_wires, 4);
assert_eq!(layer.reps, 2);
assert_eq!(layer.ry_gates.len(), 3);
assert_eq!(layer.ry_gates[0].len(), 4);
}
#[test]
fn test_efficient_su2_creation() {
let layer = EfficientSU2Layer::new(3, 2, EntanglementPattern::Circular);
assert_eq!(layer.n_wires, 3);
assert_eq!(layer.reps, 2);
assert_eq!(layer.ry_gates.len(), 3);
assert_eq!(layer.rz_gates.len(), 3);
}
#[test]
fn test_two_local_creation() {
let rotations = vec![RotationType::RY, RotationType::RZ];
let layer = TwoLocalLayer::new(4, 2, rotations, EntanglementPattern::Linear);
assert_eq!(layer.n_wires, 4);
assert_eq!(layer.reps, 2);
assert_eq!(layer.parameters.len(), 24);
}
#[test]
fn test_real_amplitudes_parameters() {
let layer = RealAmplitudesLayer::new(3, 2, EntanglementPattern::Linear);
let params = layer.parameters();
assert_eq!(params.len(), 9);
}
#[test]
fn test_efficient_su2_parameters() {
let layer = EfficientSU2Layer::new(3, 2, EntanglementPattern::Linear);
let params = layer.parameters();
assert_eq!(params.len(), 18);
}
}