use std::{fmt, ops::BitOr};
use crate::sop::Ecube;
use crate::Lut;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Soes {
num_vars: usize,
cubes: Vec<Ecube>,
}
impl Soes {
pub fn num_vars(&self) -> usize {
self.num_vars
}
pub fn zero(num_vars: usize) -> Soes {
Soes {
num_vars,
cubes: vec![],
}
}
pub fn one(num_vars: usize) -> Soes {
Soes {
num_vars,
cubes: vec![Ecube::one()],
}
}
pub fn num_cubes(&self) -> usize {
self.cubes.len()
}
pub fn num_lits(&self) -> usize {
let mut ret = 0;
for c in &self.cubes {
ret += c.num_lits();
}
ret
}
pub fn is_zero(&self) -> bool {
self.cubes.is_empty()
}
pub fn is_one(&self) -> bool {
match self.cubes.first() {
Some(c) => c.is_one(),
None => false,
}
}
pub fn nth_var(num_vars: usize, var: usize) -> Soes {
Soes {
num_vars,
cubes: vec![Ecube::nth_var(var)],
}
}
pub fn nth_var_inv(num_vars: usize, var: usize) -> Soes {
Soes {
num_vars,
cubes: vec![Ecube::nth_var_inv(var)],
}
}
pub fn from_cubes(num_vars: usize, cubes: Vec<Ecube>) -> Soes {
for c in &cubes {
for v in c.vars() {
assert!(v < num_vars);
}
}
Soes { num_vars, cubes }
}
pub fn cubes(&self) -> &[Ecube] {
&self.cubes
}
pub fn value(&self, mask: usize) -> bool {
let mut ret = false;
for c in &self.cubes {
ret |= c.value(mask);
}
ret
}
fn or(a: &Soes, b: &Soes) -> Soes {
assert_eq!(a.num_vars, b.num_vars);
let mut cubes = a.cubes.clone();
cubes.extend(&b.cubes);
Soes {
num_vars: a.num_vars,
cubes,
}
}
}
impl BitOr<Soes> for Soes {
type Output = Soes;
fn bitor(self, rhs: Soes) -> Self::Output {
Soes::or(&self, &rhs)
}
}
impl BitOr<Soes> for &Soes {
type Output = Soes;
fn bitor(self, rhs: Soes) -> Self::Output {
Soes::or(self, &rhs)
}
}
impl BitOr<&Soes> for &Soes {
type Output = Soes;
fn bitor(self, rhs: &Soes) -> Self::Output {
Soes::or(self, rhs)
}
}
impl BitOr<&Soes> for Soes {
type Output = Soes;
fn bitor(self, rhs: &Soes) -> Self::Output {
Soes::or(&self, rhs)
}
}
impl fmt::Display for Soes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_zero() {
write!(f, "0")?;
return Ok(());
}
let s = self
.cubes
.iter()
.map(|c| c.to_string())
.collect::<Vec<_>>()
.join(" | ");
write!(f, "{}", s)
}
}
impl From<&Soes> for Lut {
fn from(value: &Soes) -> Self {
let mut ret = Lut::zero(value.num_vars());
let mx = ret.num_bits();
for mask in 0..mx {
if value.value(mask) {
ret.set_bit(mask);
}
}
ret
}
}
impl From<Soes> for Lut {
fn from(value: Soes) -> Self {
Lut::from(&value)
}
}
#[cfg(test)]
mod tests {
use super::Ecube;
use super::Soes;
#[test]
fn test_zero_one() {
assert!(Soes::zero(32).is_zero());
assert!(!Soes::one(32).is_zero());
assert!(!Soes::zero(32).is_one());
assert!(Soes::one(32).is_one());
for i in 0..32 {
assert!(!Soes::nth_var(32, i).is_zero());
assert!(!Soes::nth_var(32, i).is_one());
assert!(!Soes::nth_var_inv(32, i).is_zero());
assert!(!Soes::nth_var_inv(32, i).is_one());
}
}
#[test]
fn test_display() {
let s = Soes::from_cubes(
6,
vec![
Ecube::from_vars(&[1, 2, 3], false),
Ecube::from_vars(&[2, 1, 5], true),
],
);
assert_eq!(format!("{:}", s), "x1 ^ x2 ^ x3 | 1 ^ x1 ^ x2 ^ x5");
}
}