use crate::errors::CircuitError;
use crate::pipeline::*;
use crate::types::Precision;
use crate::Complex;
use std::cmp::Ordering;
use std::fmt;
use std::rc::Rc;
#[derive(Debug)]
pub enum Parent {
Owned(Vec<Register>, Option<StateModifier>),
Shared(Rc<Register>),
}
pub struct Register {
pub indices: Vec<u64>,
pub(crate) parent: Option<Parent>,
pub(crate) deps: Option<Vec<Rc<Register>>>,
pub(crate) id: u64,
}
impl Register {
pub(crate) fn new(id: u64, indices: Vec<u64>) -> Result<Register, CircuitError> {
if indices.is_empty() {
CircuitError::make_str_err("Register must have at least one index assigned.")
} else {
Ok(Register {
indices,
parent: None,
deps: None,
id,
})
}
}
pub fn handle(&self) -> RegisterHandle {
RegisterHandle {
indices: self.indices.clone(),
}
}
pub fn merge_with_modifier(
id: u64,
registers: Vec<Register>,
modifier: Option<StateModifier>,
) -> Result<Register, CircuitError> {
if registers.is_empty() {
CircuitError::make_str_err("Cannot merge zero registers.")
} else {
let all_indices = registers
.iter()
.map(|r| r.indices.clone())
.flatten()
.collect();
Ok(Register {
indices: all_indices,
parent: Some(Parent::Owned(registers, modifier)),
deps: None,
id,
})
}
}
pub fn split(
ida: u64,
idb: u64,
r: Register,
indices: &[u64],
) -> Result<(Register, Option<Register>), CircuitError> {
for indx in indices {
if *indx > r.n() {
let message = format!(
"All indices for splitting must be below r.n={:?}, found indx={:?}",
r.n(),
*indx
);
return CircuitError::make_err(message);
}
}
if indices.len() == r.indices.len() {
CircuitError::make_str_err("Cannot split out all indices into own Registers.")
} else if indices.is_empty() {
CircuitError::make_str_err("Must provide indices to split.")
} else {
let selected_indices: Vec<u64> =
indices.iter().map(|i| r.indices[(*i) as usize]).collect();
Self::split_absolute(ida, idb, r, &selected_indices)
}
}
pub fn split_absolute(
ida: u64,
idb: u64,
r: Register,
selected_indices: &[u64],
) -> Result<(Register, Option<Register>), CircuitError> {
if selected_indices.is_empty() {
return CircuitError::make_str_err("Must provide indices to split.");
}
for indx in selected_indices {
if !r.indices.contains(indx) {
let message = format!(
"Index {:?} not found in Register with indices {:?}",
indx, r.indices
);
return CircuitError::make_err(message);
}
}
let remaining: Vec<_> = r
.indices
.clone()
.into_iter()
.filter(|x| !selected_indices.contains(x))
.collect();
if !remaining.is_empty() {
let shared_parent = Rc::new(r);
Ok((
Register {
indices: selected_indices.to_vec(),
parent: Some(Parent::Shared(shared_parent.clone())),
deps: None,
id: ida,
},
Some(Register {
indices: remaining,
parent: Some(Parent::Shared(shared_parent)),
deps: None,
id: idb,
}),
))
} else {
Ok((
Register {
indices: selected_indices.to_vec(),
parent: Some(Parent::Owned(vec![r], None)),
deps: None,
id: ida,
},
None,
))
}
}
pub fn make_measurement_handle(id: u64, r: Register) -> (Register, MeasurementHandle) {
let indices = r.indices.clone();
let shared_parent = Rc::new(r);
let handle = MeasurementHandle::new(&shared_parent);
(
Register {
indices,
parent: Some(Parent::Shared(shared_parent)),
deps: None,
id,
},
handle,
)
}
pub fn add_deps(r: Register, deps: Vec<Rc<Register>>) -> Register {
Register {
indices: r.indices,
parent: r.parent,
deps: Some(deps),
id: r.id,
}
}
pub fn n(&self) -> u64 {
self.indices.len() as u64
}
}
impl Eq for Register {}
impl PartialEq for Register {
fn eq(&self, other: &Register) -> bool {
self.id == other.id
}
}
impl Ord for Register {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for Register {
fn partial_cmp(&self, other: &Register) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl fmt::Debug for Register {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let int_strings = self
.indices
.iter()
.map(|x| x.clone().to_string())
.collect::<Vec<String>>();
write!(
f,
"Register[{}][{}]",
self.id.to_string(),
int_strings.join(", ")
)
}
}
#[derive(Debug)]
pub struct RegisterHandle {
indices: Vec<u64>,
}
impl RegisterHandle {
pub fn n(&self) -> u64 {
self.indices.len() as u64
}
pub fn make_init_from_index<P: Precision>(
&self,
index: u64,
) -> Result<RegisterInitialState<P>, CircuitError> {
let n = self.indices.len();
if index < (1 << n) as u64 {
Ok((self.indices.clone(), InitialState::Index(index)))
} else {
let message = format!(
"Index {:?} is too large, must be less than 2^{:?}",
index, n
);
CircuitError::make_err(message)
}
}
pub fn make_init_from_state<P: Precision>(
&self,
state: Vec<Complex<P>>,
) -> Result<RegisterInitialState<P>, CircuitError> {
let n = self.indices.len();
if state.len() == 1 << n {
Ok((self.indices.clone(), InitialState::FullState(state)))
} else {
let message = format!(
"State not correct size for RegisterHandle (is {}, must be 2^{})",
state.len(),
n
);
CircuitError::make_err(message)
}
}
}