use std::fmt;
use super::constraint::Constraint;
#[derive(Clone,Debug,PartialEq)]
pub struct Polynomial {
terms: Vec<Term>
}
impl Polynomial {
pub fn var(vindex: usize) -> Polynomial {
let term = Term::new(1,&[vindex]);
Self{terms: vec![term]}
}
pub fn sign(&self) -> Option<bool> {
let mut sign = false;
for (i,t) in self.terms.iter().enumerate() {
let ith = t.coefficient >= 0;
if i == 0 { sign = ith; }
else if sign != ith {
return None;
}
}
Some(sign)
}
pub fn constant(&self) -> isize {
for t in &self.terms {
if t.vars.len() == 0 {
return t.coefficient;
}
}
0
}
pub fn is_zero(&self) -> Option<bool> {
if self.terms.len() == 0 { Some(true) }
else if self.sign() != None && self.constant() != 0 {
Some(false)
} else {
None
}
}
pub fn above_zero(&self) -> Option<bool> {
if self.terms.len() == 0 { Some(false) }
else if self.sign() == Some(true) && self.constant() != 0 {
Some(true)
} else if self.sign() == Some(false) {
Some(false)
} else {
None
}
}
pub fn below_zero(&self) -> Option<bool> {
if self.terms.len() == 0 { Some(false) }
else if self.sign() == Some(false) && self.constant() != 0 {
Some(true)
} else if self.sign() == Some(true) {
Some(false)
} else {
None
}
}
pub fn negate(mut self) -> Self {
for t in &mut self.terms {
t.negate();
}
self
}
pub fn add(mut self, rhs: &Polynomial) -> Self {
for t in &rhs.terms {
self.internal_add(t);
}
self
}
pub fn sub(mut self, rhs: &Polynomial) -> Self {
for t in &rhs.terms {
self.internal_sub(t);
}
self
}
pub fn mul(mut self, rhs: &Polynomial) -> Self {
let mut ts = Vec::new();
std::mem::swap(&mut ts, &mut self.terms);
for t1 in ts.into_iter() {
for t2 in &rhs.terms {
let t3 = t1.clone().mul(&t2);
self.internal_add(&t3);
}
}
self
}
pub fn equals(mut self, rhs: Polynomial) -> Constraint {
Constraint::eq_zero(self.sub(&rhs))
}
pub fn not_equals(mut self, rhs: Polynomial) -> Constraint {
Constraint::neq_zero(self.sub(&rhs))
}
pub fn less_than(mut self, rhs: Polynomial) -> Constraint {
Constraint::gt_zero(rhs.sub(&self))
}
pub fn less_than_or_equals(mut self, rhs: Polynomial) -> Constraint {
Constraint::gteq_zero(rhs.sub(&self))
}
pub fn eval(&self, vals: &[usize]) -> isize {
let mut acc = 0;
for t in &self.terms {
acc += t.eval(vals);
}
acc
}
pub fn substitute(&self, var: usize, val: &Polynomial) -> Polynomial {
let mut r = Self{terms: Vec::new()};
for t in &self.terms {
let p = t.substitute(var,val);
r = r + p;
}
r
}
fn internal_add(&mut self, term: &Term) {
for (i,t) in &mut self.terms.iter_mut().enumerate() {
if t.vars == term.vars {
t.coefficient += term.coefficient;
if t.coefficient == 0 {
self.terms.remove(i);
}
return;
}
}
self.terms.push(term.clone());
self.terms.sort();
}
fn internal_sub(&mut self, term: &Term) {
for (i,t) in &mut self.terms.iter_mut().enumerate() {
if t.vars == term.vars {
t.coefficient -= term.coefficient;
if t.coefficient == 0 {
self.terms.remove(i);
}
return;
}
}
let mut t = term.clone();
t.negate();
self.terms.push(t);
self.terms.sort();
}
}
impl fmt::Display for Polynomial {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i,t) in self.terms.iter().enumerate() {
if i != 0 { write!(f,"+")?; }
write!(f,"{t}")?;
}
Ok(())
}
}
impl From<usize> for Polynomial {
fn from(val: usize) -> Self {
if val == 0 {
Self{terms: Vec::new()}
} else {
let term = Term{coefficient: val as isize, vars: Vec::new()};
Self{terms: vec![term]}
}
}
}
impl From<i32> for Polynomial {
fn from(val: i32) -> Self {
if val == 0 {
Self{terms: Vec::new()}
} else {
let term = Term{coefficient: val as isize, vars: Vec::new()};
Self{terms: vec![term]}
}
}
}
impl std::ops::Add<usize> for Polynomial {
type Output = Self;
fn add(self, rhs: usize) -> Self {
let r = Polynomial::from(rhs);
self.add(&r)
}
}
impl std::ops::Add for Polynomial {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self.add(&rhs)
}
}
impl std::ops::Sub<usize> for Polynomial {
type Output = Self;
fn sub(self, rhs: usize) -> Self {
let r = Polynomial::from(rhs);
self.sub(&r)
}
}
impl std::ops::Sub for Polynomial {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self.sub(&rhs)
}
}
impl std::ops::Mul<usize> for Polynomial {
type Output = Self;
fn mul(self, rhs: usize) -> Self {
let r = Polynomial::from(rhs);
self.mul(&r)
}
}
impl std::ops::Mul for Polynomial {
type Output = Self;
fn mul(self, rhs: Polynomial) -> Self {
self.mul(&rhs)
}
}
#[derive(Clone,Debug,Eq,Ord,PartialEq,PartialOrd)]
pub struct Term {
coefficient: isize,
vars: Vec<usize>
}
impl Term {
pub fn new(coefficient: isize, vars: &[usize]) -> Self {
Self{coefficient, vars: vars.to_vec()}
}
pub fn negate(&mut self) {
self.coefficient = -self.coefficient;
}
pub fn mul(mut self, rhs: &Term) -> Self {
self.coefficient *= rhs.coefficient;
self.vars.extend_from_slice(&rhs.vars);
self.vars.sort();
self
}
pub fn eval(&self, vals: &[usize]) -> isize {
let mut r = self.coefficient;
for v in &self.vars {
r *= vals[*v] as isize;
}
r
}
pub fn substitute(&self, var: usize, val: &Polynomial) -> Polynomial {
let mut nvars = Vec::new();
let mut count = 0;
for v in &self.vars {
if *v == var {
count = count + 1;
} else {
nvars.push(*v);
}
}
let nterm = Self{coefficient: self.coefficient, vars: nvars};
let mut r = Polynomial{terms: vec![nterm]};
for i in 0..count {
r = r * val.clone();
}
r
}
}
impl fmt::Display for Term {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.coefficient)?;
for idx in &self.vars {
let v = (*idx as u32) % 3;
let w = (*idx as u32) / 3;
let a = ('x' as u32) + v;
let c = char::from_u32(a).unwrap();
write!(f,"*{c}{w}")?;
}
Ok(())
}
}