use crate::error::{Error, Result, checked_product};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(try_from = "Vec<usize>", into = "Vec<usize>")]
pub struct Register {
dimensions: Vec<usize>,
size: usize,
}
impl Register {
pub fn new(dimensions: Vec<usize>) -> Result<Self> {
if dimensions.is_empty() || dimensions.iter().any(|&d| d < 2) {
return Err(Error::InvalidDimensions(format!("{dimensions:?}")));
}
let size = checked_product(dimensions.iter().copied())?;
Ok(Self { dimensions, size })
}
pub fn qubits(count: usize) -> Result<Self> {
if count >= usize::BITS as usize {
return Err(Error::Overflow);
}
Self::new(vec![2; count])
}
pub fn dimensions(&self) -> &[usize] {
&self.dimensions
}
pub fn wires(&self) -> usize {
self.dimensions.len()
}
pub fn size(&self) -> usize {
self.size
}
pub fn encode(&self, digits: &[usize]) -> Result<usize> {
if digits.len() != self.wires() {
return Err(Error::Basis);
}
let mut index = 0;
for (&x, &d) in digits.iter().zip(&self.dimensions) {
if x >= d {
return Err(Error::Basis);
}
index = index * d + x;
}
Ok(index)
}
pub fn decode(&self, mut index: usize) -> Result<Vec<usize>> {
if index >= self.size {
return Err(Error::Basis);
}
let mut digits = vec![0; self.wires()];
for (x, &d) in digits.iter_mut().zip(&self.dimensions).rev() {
*x = index % d;
index /= d;
}
Ok(digits)
}
pub fn local_size(&self, wires: &[usize]) -> Result<usize> {
if wires.is_empty() {
return Err(Error::Wires("empty target list".into()));
}
for (i, &wire) in wires.iter().enumerate() {
if wire >= self.wires() || wires[..i].contains(&wire) {
return Err(Error::Wires(format!("{wires:?}")));
}
}
checked_product(wires.iter().map(|&w| self.dimensions[w]))
}
pub(crate) fn permutation(&self, wires: &[usize]) -> Result<(Vec<i64>, Vec<i64>)> {
self.local_size(wires)?;
if self.size > i32::MAX as usize {
return Err(Error::Unsupported(
"dense gather indices exceed signed 32-bit range".into(),
));
}
let order: Vec<_> = (0..self.wires())
.filter(|w| !wires.contains(w))
.chain(wires.iter().copied())
.collect();
let mut forward = vec![0; self.size];
let mut inverse = vec![0; self.size];
for (old, inv) in inverse.iter_mut().enumerate() {
let digits = self.decode(old)?;
let packed = order
.iter()
.fold(0, |index, &w| index * self.dimensions[w] + digits[w]);
forward[packed] = old as i64;
*inv = packed as i64;
}
Ok((forward, inverse))
}
}
impl TryFrom<Vec<usize>> for Register {
type Error = Error;
fn try_from(value: Vec<usize>) -> Result<Self> {
Self::new(value)
}
}
impl From<Register> for Vec<usize> {
fn from(value: Register) -> Self {
value.dimensions
}
}