#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::iter::FromIterator;
pub trait Op: Clone + Debug {
type Vars: FromIterator<usize> + AsRef<[usize]> + AsMut<[usize]> + Debug;
type SubState: FromIterator<bool> + AsRef<[bool]> + AsMut<[bool]> + Debug;
fn diagonal<A, B>(vars: A, bond: usize, state: B, constant: bool) -> Self
where
A: Into<Self::Vars>,
B: Into<Self::SubState>;
fn offdiagonal<A, B, C>(vars: A, bond: usize, inputs: B, outputs: C, constant: bool) -> Self
where
A: Into<Self::Vars>,
B: Into<Self::SubState>,
C: Into<Self::SubState>;
fn make_vars<V>(vars: V) -> Self::Vars
where
V: IntoIterator<Item = usize>,
{
vars.into_iter().collect()
}
fn make_substate<S>(state: S) -> Self::SubState
where
S: IntoIterator<Item = bool>,
{
state.into_iter().collect()
}
fn index_of_var(&self, var: usize) -> Option<usize>;
fn is_diagonal(&self) -> bool {
self.get_inputs() == self.get_outputs()
}
fn get_vars(&self) -> &[usize];
fn get_bond(&self) -> usize;
fn get_inputs(&self) -> &[bool];
fn get_outputs(&self) -> &[bool];
fn clone_and_edit_in_out<F>(&self, f: F) -> Self
where
F: Fn(&mut [bool], &mut [bool]);
fn clone_and_edit_in_out_symmetric<F>(&self, f: F) -> Self
where
F: Fn(&mut [bool]);
fn edit_in_out<F>(&mut self, f: F)
where
F: Fn(&mut [bool], &mut [bool]);
fn edit_in_out_symmetric<F>(&mut self, f: F)
where
F: Fn(&mut [bool]);
fn clone_inputs(&self) -> Self::SubState;
fn clone_outputs(&self) -> Self::SubState;
fn is_constant(&self) -> bool;
}
pub trait OpNode<O: Op> {
fn get_op(&self) -> O;
fn get_op_ref(&self) -> &O;
fn get_op_mut(&mut self) -> &mut O;
}
pub trait OpContainerConstructor {
fn new(nvars: usize) -> Self;
fn new_with_bonds(nvars: usize, nbonds: usize) -> Self;
}
pub trait OpContainer {
type Op: Op;
fn get_cutoff(&self) -> usize;
fn set_cutoff(&mut self, cutoff: usize);
fn get_n(&self) -> usize;
fn get_nvars(&self) -> usize;
fn get_pth(&self, p: usize) -> Option<&Self::Op>;
fn get_count(&self, bond: usize) -> usize;
fn verify(&self, state: &[bool]) -> bool {
let mut rolling_state = state.to_vec();
for p in 0..self.get_cutoff() {
let op = self.get_pth(p);
if let Some(op) = op {
for (v, inp) in op.get_vars().iter().zip(op.get_inputs().iter()) {
if rolling_state[*v] != *inp {
return false;
}
}
op.get_vars()
.iter()
.zip(op.get_outputs().iter())
.for_each(|(v, out)| {
rolling_state[*v] = *out;
})
}
}
rolling_state
.into_iter()
.zip(state.iter().cloned())
.all(|(a, b)| a == b)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum OpType<SubState>
where
SubState: Clone + Debug + FromIterator<bool> + AsRef<[bool]> + AsMut<[bool]>,
{
DIAGONAL(SubState),
OFFDIAGONAL(SubState, SubState),
}
impl<SubState> OpType<SubState>
where
SubState: Clone + Debug + FromIterator<bool> + AsRef<[bool]> + AsMut<[bool]>,
{
fn edit_states<F>(&mut self, f: F)
where
F: Fn(&mut [bool], &mut [bool]),
{
let (inputs, outputs) = match self {
OpType::DIAGONAL(state) => {
let mut inputs = state.clone();
let mut outputs = state.clone();
f(inputs.as_mut(), outputs.as_mut());
(inputs, outputs)
}
OpType::OFFDIAGONAL(inputs, outputs) => {
let mut inputs = inputs.clone();
let mut outputs = outputs.clone();
f(inputs.as_mut(), outputs.as_mut());
(inputs, outputs)
}
};
*self = if inputs.as_ref() == outputs.as_ref() {
Self::DIAGONAL(inputs)
} else {
Self::OFFDIAGONAL(inputs, outputs)
};
}
fn edit_states_symmetric<F>(&mut self, f: F)
where
F: Fn(&mut [bool]),
{
match self {
OpType::DIAGONAL(state) => {
f(state.as_mut());
}
OpType::OFFDIAGONAL(inputs, outputs) => {
f(inputs.as_mut());
f(outputs.as_mut());
}
};
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct BasicOp<Vars, SubState>
where
Vars: FromIterator<usize> + AsRef<[usize]> + AsMut<[usize]> + Clone + Debug,
SubState: FromIterator<bool> + AsRef<[bool]> + AsMut<[bool]> + Clone + Debug,
{
vars: Vars,
bond: usize,
in_out: OpType<SubState>,
constant: bool,
}
impl<Vars, SubState> Op for BasicOp<Vars, SubState>
where
Vars: FromIterator<usize> + AsRef<[usize]> + AsMut<[usize]> + Clone + Debug,
SubState: FromIterator<bool> + AsRef<[bool]> + AsMut<[bool]> + Clone + Debug,
{
type Vars = Vars;
type SubState = SubState;
fn diagonal<A, B>(vars: A, bond: usize, state: B, constant: bool) -> Self
where
A: Into<Self::Vars>,
B: Into<Self::SubState>,
{
Self {
vars: vars.into(),
bond,
in_out: OpType::DIAGONAL(state.into()),
constant,
}
}
fn offdiagonal<A, B, C>(vars: A, bond: usize, inputs: B, outputs: C, constant: bool) -> Self
where
A: Into<Self::Vars>,
B: Into<Self::SubState>,
C: Into<Self::SubState>,
{
Self {
vars: vars.into(),
bond,
in_out: OpType::OFFDIAGONAL(inputs.into(), outputs.into()),
constant,
}
}
fn is_diagonal(&self) -> bool {
matches!(&self.in_out, OpType::DIAGONAL(_))
}
fn index_of_var(&self, var: usize) -> Option<usize> {
let res = self
.vars
.as_ref()
.iter()
.enumerate()
.try_for_each(|(indx, v)| if *v == var { Err(indx) } else { Ok(()) });
match res {
Ok(_) => None,
Err(v) => Some(v),
}
}
fn get_vars(&self) -> &[usize] {
self.vars.as_ref()
}
fn get_bond(&self) -> usize {
self.bond
}
fn get_inputs(&self) -> &[bool] {
match &self.in_out {
OpType::DIAGONAL(state) => state.as_ref(),
OpType::OFFDIAGONAL(state, _) => state.as_ref(),
}
}
fn get_outputs(&self) -> &[bool] {
match &self.in_out {
OpType::DIAGONAL(state) => state.as_ref(),
OpType::OFFDIAGONAL(_, state) => state.as_ref(),
}
}
fn clone_and_edit_in_out<F>(&self, f: F) -> Self
where
F: Fn(&mut [bool], &mut [bool]),
{
let (mut inputs, mut outputs) = match &self.in_out {
OpType::DIAGONAL(state) => {
let inputs = state.clone();
let outputs = state.clone();
(inputs, outputs)
}
OpType::OFFDIAGONAL(inputs, outputs) => {
let inputs = inputs.clone();
let outputs = outputs.clone();
(inputs, outputs)
}
};
f(inputs.as_mut(), outputs.as_mut());
let all_eq = inputs.as_ref() == outputs.as_ref();
let in_out = if all_eq {
OpType::DIAGONAL(inputs)
} else {
OpType::OFFDIAGONAL(inputs, outputs)
};
Self {
vars: self.vars.clone(),
bond: self.bond,
in_out,
constant: self.constant,
}
}
fn clone_and_edit_in_out_symmetric<F>(&self, f: F) -> Self
where
F: Fn(&mut [bool]),
{
let in_out = match &self.in_out {
OpType::DIAGONAL(state) => {
let mut inputs = state.clone();
f(inputs.as_mut());
OpType::DIAGONAL(inputs)
}
OpType::OFFDIAGONAL(inputs, outputs) => {
let mut inputs = inputs.clone();
let mut outputs = outputs.clone();
f(inputs.as_mut());
f(outputs.as_mut());
OpType::OFFDIAGONAL(inputs, outputs)
}
};
Self {
vars: self.vars.clone(),
bond: self.bond,
in_out,
constant: self.constant,
}
}
fn clone_inputs(&self) -> Self::SubState {
match &self.in_out {
OpType::DIAGONAL(state) => state.clone(),
OpType::OFFDIAGONAL(state, _) => state.clone(),
}
}
fn clone_outputs(&self) -> Self::SubState {
match &self.in_out {
OpType::DIAGONAL(state) => state.clone(),
OpType::OFFDIAGONAL(_, state) => state.clone(),
}
}
fn is_constant(&self) -> bool {
self.constant
}
fn edit_in_out<F>(&mut self, f: F)
where
F: Fn(&mut [bool], &mut [bool]),
{
self.in_out.edit_states(f)
}
fn edit_in_out_symmetric<F>(&mut self, f: F)
where
F: Fn(&mut [bool]),
{
self.in_out.edit_states_symmetric(f)
}
}