rqism 0.4.1

A multi-backend quantum circuit simulator
Documentation
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};

use crate::sparse_mat::SMat;
use num::{complex::ComplexFloat, Complex};

/// A sparse quantum state that stores only non-zero components of the state.
/// Now, it is a thin wrapper around sparse_mat::SMat.
#[derive(Debug, Clone)]
pub struct SQS {
    pub mat: SMat,
    pub n: u32,
}

impl SQS {
    pub fn new(n: u32) -> Self {
        let mat = SMat::zeros((1, n));

        Self { mat, n }
    }

    pub fn set(&self, i: u32, v: Complex<f32>) {
        if i > self.n {
            panic!(
                "attempting to set value at index {} but length is {}",
                i, self.n
            );
        }

        self.mat.set_unchecked(1, i, v);
    }

    pub fn get(&self, i: u32) -> Complex<f32> {
        if i > self.n {
            panic!(
                "attempting to get value at index {} but length is {}",
                i, self.n
            );
        }

        self.mat.get_unchecked(1, i)
    }

    pub fn dot(&self, rhs: &SMat) -> Self {
        Self {
            mat: self.mat.dot(rhs),
            n: self.n,
        }
    }

    pub fn to_vec(&self) -> Vec<Complex<f32>> {
        (0..self.n).map(|x| self.get(x)).collect()
    }

    pub fn fill_zero(&mut self) {
        *self = Self::new(self.n);
    }

    pub fn iter(&self) -> SQSIterator {
        SQSIterator { sqs: self, n: 0 }
    }
}

/// iterator over a sparse quantum state
pub struct SQSIterator<'a> {
    sqs: &'a SQS,
    n: u32,
}

impl Iterator for SQSIterator<'_> {
    type Item = Complex<f32>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.n >= self.sqs.n {
            return None;
        }

        let r = Some(self.sqs.get(self.n));

        self.n += 1;

        r
    }
}

// not sure if this implementation is proper, but it works without UB
unsafe impl Send for SQS {}
unsafe impl Sync for SQS {}

impl Add for SQS {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        if self.n != rhs.n {
            panic!("SQSs must be of the same length to be added.");
        }

        let c = self.clone();

        for i in 0..rhs.n {
            c.set(i, c.get(i) + rhs.get(i));
        }

        c
    }
}

impl Sub for SQS {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        if self.n != rhs.n {
            panic!("SQSs must be of the same length to be added.");
        }

        let c = self.clone();

        for i in 0..rhs.n {
            c.set(i, c.get(i) - rhs.get(i));
        }

        c
    }
}

impl Mul<Complex<f32>> for SQS {
    type Output = Self;

    fn mul(self, rhs: Complex<f32>) -> Self::Output {
        let c = self.clone();

        for i in 0..c.n {
            c.set(i, c.get(i) * rhs);
        }

        c
    }
}

impl Div<Complex<f32>> for SQS {
    type Output = Self;

    fn div(self, rhs: Complex<f32>) -> Self::Output {
        let c = self.clone();
        let k = rhs.recip();

        for i in 0..c.n {
            c.set(i, c.get(i) * k);
        }

        c
    }
}

impl AddAssign for SQS {
    fn add_assign(&mut self, rhs: Self) {
        if self.n != rhs.n {
            panic!("SQSs must be of the same length to be added.");
        }

        for i in 0..self.n {
            self.set(i, self.get(i) + rhs.get(i));
        }
    }
}

impl SubAssign for SQS {
    fn sub_assign(&mut self, rhs: Self) {
        if self.n != rhs.n {
            panic!("SQSs must be of the same length to be added.");
        }

        for i in 0..self.n {
            self.set(i, self.get(i) - rhs.get(i));
        }
    }
}

impl MulAssign<Complex<f32>> for SQS {
    fn mul_assign(&mut self, rhs: Complex<f32>) {
        for i in 0..self.n {
            self.set(i, self.get(i) * rhs);
        }
    }
}

impl DivAssign<Complex<f32>> for SQS {
    fn div_assign(&mut self, rhs: Complex<f32>) {
        let k = rhs.recip();

        for i in 0..self.n {
            self.set(i, self.get(i) * k);
        }
    }
}