mod coefficient;
pub mod default;
use crate::{
coefficient::{Coefficient, CoefficientView},
parser::Token,
printer::AtomPrinter,
state::{BufferHandle, ResettableBuffer, State, Workspace},
};
use std::{
cmp::Ordering,
hash::Hash,
ops::{DerefMut, Range},
};
use self::default::Linear;
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Identifier(u32);
impl Identifier {
pub(crate) const fn init(value: u32) -> Self {
Identifier(value)
}
}
impl std::fmt::Debug for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.0))
}
}
impl From<u32> for Identifier {
fn from(value: u32) -> Self {
Identifier(value)
}
}
impl Identifier {
pub fn to_u32(&self) -> u32 {
self.0
}
}
pub trait AtomSet: Copy + Clone + PartialEq + Eq + Hash + Send + 'static {
type N<'a>: Num<'a, P = Self>;
type V<'a>: Var<'a, P = Self>;
type F<'a>: Fun<'a, P = Self>;
type P<'a>: Pow<'a, P = Self>;
type M<'a>: Mul<'a, P = Self>;
type A<'a>: Add<'a, P = Self>;
type ON: OwnedNum<P = Self>;
type OV: OwnedVar<P = Self>;
type OF: OwnedFun<P = Self>;
type OP: OwnedPow<P = Self>;
type OM: OwnedMul<P = Self>;
type OA: OwnedAdd<P = Self>;
type S<'a>: ListSlice<'a, P = Self>;
}
pub trait Convert<P: AtomSet> {
fn to_owned_var(self) -> P::OV;
fn to_owned_num(self) -> P::ON;
fn to_owned_fun(self) -> P::OF;
fn to_owned_pow(self) -> P::OP;
fn to_owned_add(self) -> P::OA;
fn to_owned_mul(self) -> P::OM;
}
pub trait OwnedNum: Clone + PartialEq + Hash + Send + ResettableBuffer + Convert<Self::P> {
type P: AtomSet;
fn set_from_coeff(&mut self, num: Coefficient);
fn set_from_view(&mut self, a: &<Self::P as AtomSet>::N<'_>);
fn add(&mut self, other: &<Self::P as AtomSet>::N<'_>, state: &State);
fn mul(&mut self, other: &<Self::P as AtomSet>::N<'_>, state: &State);
fn to_num_view(&self) -> <Self::P as AtomSet>::N<'_>;
fn as_view(&self) -> AtomView<Self::P>;
}
pub trait OwnedVar: Clone + PartialEq + Hash + Send + ResettableBuffer + Convert<Self::P> {
type P: AtomSet;
fn set_from_id(&mut self, id: Identifier);
fn set_from_view(&mut self, view: &<Self::P as AtomSet>::V<'_>);
fn to_var_view(&self) -> <Self::P as AtomSet>::V<'_>;
fn as_view(&self) -> AtomView<Self::P>;
}
pub trait OwnedFun: Clone + PartialEq + Hash + Send + ResettableBuffer + Convert<Self::P> {
type P: AtomSet;
fn set_from_view(&mut self, view: &<Self::P as AtomSet>::F<'_>);
fn set_from_name(&mut self, id: Identifier);
fn set_dirty(&mut self, dirty: bool);
fn add_arg(&mut self, other: AtomView<Self::P>);
fn to_fun_view(&self) -> <Self::P as AtomSet>::F<'_>;
fn as_view(&self) -> AtomView<Self::P>;
}
pub trait OwnedPow: Clone + PartialEq + Hash + Send + ResettableBuffer + Convert<Self::P> {
type P: AtomSet;
fn set_from_view(&mut self, view: &<Self::P as AtomSet>::P<'_>);
fn set_from_base_and_exp(&mut self, base: AtomView<'_, Self::P>, exp: AtomView<'_, Self::P>);
fn set_dirty(&mut self, dirty: bool);
fn to_pow_view(&self) -> <Self::P as AtomSet>::P<'_>;
fn as_view(&self) -> AtomView<Self::P>;
}
pub trait OwnedMul: Clone + PartialEq + Hash + Send + ResettableBuffer + Convert<Self::P> {
type P: AtomSet;
fn set_dirty(&mut self, dirty: bool);
fn set_has_coefficient(&mut self, has_coeff: bool);
fn set_from_view(&mut self, view: &<Self::P as AtomSet>::M<'_>);
fn extend(&mut self, other: AtomView<Self::P>);
fn replace_last(&mut self, other: AtomView<Self::P>);
fn to_mul_view(&self) -> <Self::P as AtomSet>::M<'_>;
fn as_view(&self) -> AtomView<Self::P>;
}
pub trait OwnedAdd: Clone + PartialEq + Hash + Send + ResettableBuffer + Convert<Self::P> {
type P: AtomSet;
fn set_dirty(&mut self, dirty: bool);
fn set_from_view(&mut self, view: &<Self::P as AtomSet>::A<'_>);
fn extend(&mut self, other: AtomView<Self::P>);
fn to_add_view(&self) -> <Self::P as AtomSet>::A<'_>;
fn as_view(&self) -> AtomView<Self::P>;
}
pub trait Num<'a>: Copy + Clone + Hash + for<'b> PartialEq<<Self::P as AtomSet>::N<'b>> {
type P: AtomSet;
fn is_zero(&self) -> bool;
fn is_one(&self) -> bool;
fn is_dirty(&self) -> bool;
fn get_coeff_view(&self) -> CoefficientView<'_>;
fn as_view(&self) -> AtomView<'a, Self::P>;
fn get_byte_size(&self) -> usize;
}
pub trait Var<'a>: Copy + Clone + Hash + for<'b> PartialEq<<Self::P as AtomSet>::V<'b>> {
type P: AtomSet;
fn get_name(&self) -> Identifier;
fn as_view(&self) -> AtomView<'a, Self::P>;
fn get_byte_size(&self) -> usize;
}
pub trait Fun<'a>: Copy + Clone + Hash + for<'b> PartialEq<<Self::P as AtomSet>::F<'b>> {
type P: AtomSet;
type I: Iterator<Item = AtomView<'a, Self::P>>;
fn get_name(&self) -> Identifier;
fn get_nargs(&self) -> usize;
fn is_dirty(&self) -> bool;
fn iter(&self) -> Self::I;
fn as_view(&self) -> AtomView<'a, Self::P>;
fn to_slice(&self) -> <Self::P as AtomSet>::S<'a>;
fn get_byte_size(&self) -> usize;
fn fast_cmp(&self, other: <Self::P as AtomSet>::F<'_>) -> Ordering;
}
pub trait Pow<'a>: Copy + Clone + Hash + for<'b> PartialEq<<Self::P as AtomSet>::P<'b>> {
type P: AtomSet;
fn get_base(&self) -> AtomView<'a, Self::P>;
fn get_exp(&self) -> AtomView<'a, Self::P>;
fn is_dirty(&self) -> bool;
fn get_base_exp(&self) -> (AtomView<'a, Self::P>, AtomView<'a, Self::P>);
fn as_view(&self) -> AtomView<'a, Self::P>;
fn get_byte_size(&self) -> usize;
fn to_slice(&self) -> <Self::P as AtomSet>::S<'a>;
}
pub trait Mul<'a>: Copy + Clone + Hash + for<'b> PartialEq<<Self::P as AtomSet>::M<'b>> {
type P: AtomSet;
type I: Iterator<Item = AtomView<'a, Self::P>>;
fn is_dirty(&self) -> bool;
fn get_nargs(&self) -> usize;
fn iter(&self) -> Self::I;
fn as_view(&self) -> AtomView<'a, Self::P>;
fn to_slice(&self) -> <Self::P as AtomSet>::S<'a>;
fn get_byte_size(&self) -> usize;
fn has_coefficient(&self) -> bool;
}
pub trait Add<'a>: Copy + Clone + Hash + for<'b> PartialEq<<Self::P as AtomSet>::A<'b>> {
type P: AtomSet;
type I: Iterator<Item = AtomView<'a, Self::P>>;
fn is_dirty(&self) -> bool;
fn get_nargs(&self) -> usize;
fn iter(&self) -> Self::I;
fn as_view(&self) -> AtomView<'a, Self::P>;
fn to_slice(&self) -> <Self::P as AtomSet>::S<'a>;
fn get_byte_size(&self) -> usize;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SliceType {
Add,
Mul,
Arg,
One,
Pow,
Empty,
}
pub trait ListSlice<'a>: Clone {
type P: AtomSet;
type ListSliceIterator: Iterator<Item = AtomView<'a, Self::P>>;
fn iter(&self) -> Self::ListSliceIterator;
fn from_one(view: AtomView<'a, Self::P>) -> Self;
fn get_type(&self) -> SliceType;
fn len(&self) -> usize;
fn get(&self, index: usize) -> AtomView<'a, Self::P>;
fn get_subslice(&self, range: Range<usize>) -> Self;
fn eq(&self, other: &<Self::P as AtomSet>::S<'_>) -> bool;
}
pub enum AtomView<'a, P: AtomSet = Linear> {
Num(P::N<'a>),
Var(P::V<'a>),
Fun(P::F<'a>),
Pow(P::P<'a>),
Mul(P::M<'a>),
Add(P::A<'a>),
}
impl<'a, P: AtomSet> Clone for AtomView<'a, P> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, P: AtomSet> Copy for AtomView<'a, P> {}
impl<'a, 'b, P: AtomSet> PartialEq<AtomView<'b, P>> for AtomView<'a, P> {
fn eq(&self, other: &AtomView<P>) -> bool {
match (self, other) {
(AtomView::Num(n1), AtomView::Num(n2)) => n1 == n2,
(AtomView::Var(v1), AtomView::Var(v2)) => v1 == v2,
(AtomView::Fun(f1), AtomView::Fun(f2)) => f1 == f2,
(AtomView::Pow(p1), AtomView::Pow(p2)) => p1 == p2,
(AtomView::Mul(m1), AtomView::Mul(m2)) => m1 == m2,
(AtomView::Add(a1), AtomView::Add(a2)) => a1 == a2,
_ => false,
}
}
}
impl<'a, P: AtomSet> Eq for AtomView<'a, P> {}
impl<'a, P: AtomSet> PartialOrd for AtomView<'a, P> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a, P: AtomSet> Ord for AtomView<'a, P> {
fn cmp(&self, other: &Self) -> Ordering {
self.cmp(other)
}
}
impl<'a, P: AtomSet> Hash for AtomView<'a, P> {
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
AtomView::Num(a) => a.hash(state),
AtomView::Var(a) => a.hash(state),
AtomView::Fun(a) => a.hash(state),
AtomView::Pow(a) => a.hash(state),
AtomView::Mul(a) => a.hash(state),
AtomView::Add(a) => a.hash(state),
}
}
}
pub trait AsAtomView<'a, P: AtomSet>: Sized {
fn as_atom_view(self) -> AtomView<'a, P>;
fn builder<'b>(
self,
state: &'b State,
workspace: &'b Workspace<P>,
) -> AtomBuilder<'b, BufferHandle<'b, Atom<P>>, P> {
AtomBuilder::new(self, state, workspace, workspace.new_atom())
}
fn add<'b, T: AsAtomView<'b, P>>(
self,
state: &State,
workspace: &Workspace<P>,
rhs: T,
out: &mut Atom<P>,
) {
AtomView::add(
&self.as_atom_view(),
state,
workspace,
rhs.as_atom_view(),
out,
)
}
fn mul<'b, T: AsAtomView<'b, P>>(
self,
state: &State,
workspace: &Workspace<P>,
rhs: T,
out: &mut Atom<P>,
) {
AtomView::mul(
&self.as_atom_view(),
state,
workspace,
rhs.as_atom_view(),
out,
)
}
fn div<'b, T: AsAtomView<'b, P>>(
self,
state: &State,
workspace: &Workspace<P>,
rhs: T,
out: &mut Atom<P>,
) {
AtomView::div(
&self.as_atom_view(),
state,
workspace,
rhs.as_atom_view(),
out,
)
}
fn pow<'b, T: AsAtomView<'b, P>>(
self,
state: &State,
workspace: &Workspace<P>,
rhs: T,
out: &mut Atom<P>,
) {
AtomView::pow(
&self.as_atom_view(),
state,
workspace,
rhs.as_atom_view(),
out,
)
}
fn neg(self, state: &State, workspace: &Workspace<P>, out: &mut Atom<P>) {
AtomView::neg(&self.as_atom_view(), state, workspace, out)
}
}
impl<'a, P: AtomSet> AsAtomView<'a, P> for AtomView<'a, P> {
fn as_atom_view(self) -> AtomView<'a, P> {
self
}
}
impl<'a, P: AtomSet> AsAtomView<'a, P> for &'a Atom<P> {
fn as_atom_view(self) -> AtomView<'a, P> {
self.as_view()
}
}
impl<'a, P: AtomSet> From<AtomView<'a, P>> for Atom<P> {
fn from(val: AtomView<'a, P>) -> Self {
Atom::new_from_view(&val)
}
}
impl<'a, P: AtomSet> AtomView<'a, P> {
pub fn printer<'b>(&self, state: &'b State) -> AtomPrinter<'a, 'b, P> {
AtomPrinter::new(*self, state)
}
fn add_no_norm<'b>(
&self,
workspace: &'b Workspace<P>,
rhs: AtomView<'_, P>,
) -> BufferHandle<'b, Atom<P>> {
let mut e = workspace.new_atom();
let a = e.to_add();
a.extend(*self);
a.extend(rhs);
a.set_dirty(true);
e
}
fn sub_no_norm<'b>(
&self,
workspace: &'b Workspace<P>,
rhs: AtomView<'_, P>,
) -> BufferHandle<'b, Atom<P>> {
let mut e = workspace.new_atom();
let a = e.to_add();
a.extend(*self);
a.extend(rhs.neg_no_norm(workspace).as_atom_view());
a.set_dirty(true);
e
}
fn mul_no_norm<'b>(
&self,
workspace: &'b Workspace<P>,
rhs: AtomView<'_, P>,
) -> BufferHandle<'b, Atom<P>> {
let mut e = workspace.new_atom();
let a = e.to_mul();
a.extend(*self);
a.extend(rhs);
a.set_dirty(true);
e
}
fn pow_no_norm<'b>(
&self,
workspace: &'b Workspace<P>,
exp: AtomView<'_, P>,
) -> BufferHandle<'b, Atom<P>> {
let mut e = workspace.new_atom();
let a = e.to_pow();
a.set_from_base_and_exp(*self, exp);
a.set_dirty(true);
e
}
fn div_no_norm<'b>(
&self,
workspace: &'b Workspace<P>,
div: AtomView<'_, P>,
) -> BufferHandle<'b, Atom<P>> {
self.mul_no_norm(
workspace,
div.pow_no_norm(workspace, workspace.new_num(-1).as_view())
.as_view(),
)
}
fn neg_no_norm<'b>(&self, workspace: &'b Workspace<P>) -> BufferHandle<'b, Atom<P>> {
self.mul_no_norm(workspace, workspace.new_num(-1).as_view())
}
pub fn add(
&self,
state: &State,
workspace: &Workspace<P>,
rhs: AtomView<'_, P>,
out: &mut Atom<P>,
) {
self.add_no_norm(workspace, rhs)
.as_view()
.normalize(workspace, state, out);
}
pub fn mul(
&self,
state: &State,
workspace: &Workspace<P>,
rhs: AtomView<'_, P>,
out: &mut Atom<P>,
) {
self.mul_no_norm(workspace, rhs)
.as_view()
.normalize(workspace, state, out);
}
pub fn pow(
&self,
state: &State,
workspace: &Workspace<P>,
exp: AtomView<'_, P>,
out: &mut Atom<P>,
) {
self.pow_no_norm(workspace, exp)
.as_view()
.normalize(workspace, state, out);
}
pub fn div(
&self,
state: &State,
workspace: &Workspace<P>,
div: AtomView<'_, P>,
out: &mut Atom<P>,
) {
self.div_no_norm(workspace, div)
.as_view()
.normalize(workspace, state, out);
}
pub fn neg(&self, state: &State, workspace: &Workspace<P>, out: &mut Atom<P>) {
self.neg_no_norm(workspace)
.as_view()
.normalize(workspace, state, out);
}
pub fn get_byte_size(&self) -> usize {
match self {
AtomView::Num(n) => n.get_byte_size(),
AtomView::Var(v) => v.get_byte_size(),
AtomView::Fun(f) => f.get_byte_size(),
AtomView::Pow(p) => p.get_byte_size(),
AtomView::Mul(m) => m.get_byte_size(),
AtomView::Add(a) => a.get_byte_size(),
}
}
}
#[derive(Copy, Clone)]
pub enum Atom<P: AtomSet = Linear> {
Num(P::ON),
Var(P::OV),
Fun(P::OF),
Pow(P::OP),
Mul(P::OM),
Add(P::OA),
Empty, }
impl<P: AtomSet> PartialEq for Atom<P> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Num(l0), Self::Num(r0)) => l0 == r0,
(Self::Var(l0), Self::Var(r0)) => l0 == r0,
(Self::Fun(l0), Self::Fun(r0)) => l0 == r0,
(Self::Pow(l0), Self::Pow(r0)) => l0 == r0,
(Self::Mul(l0), Self::Mul(r0)) => l0 == r0,
(Self::Add(l0), Self::Add(r0)) => l0 == r0,
_ => false,
}
}
}
impl<P: AtomSet> Eq for Atom<P> {}
impl<P: AtomSet> Hash for Atom<P> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Atom::Num(a) => a.hash(state),
Atom::Var(a) => a.hash(state),
Atom::Fun(a) => a.hash(state),
Atom::Pow(a) => a.hash(state),
Atom::Mul(a) => a.hash(state),
Atom::Add(a) => a.hash(state),
Atom::Empty => 1.hash(state),
}
}
}
impl<P: AtomSet> std::fmt::Debug for Atom<P> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_view().fmt(fmt)
}
}
impl<P: AtomSet> Atom<P> {
pub fn parse(
input: &str,
state: &mut State,
workspace: &Workspace<P>,
) -> Result<Atom<P>, String> {
Token::parse(input)?.to_atom(state, workspace)
}
pub fn new_var(id: Identifier) -> Atom<P> {
let mut owned = Self::new();
owned.to_var().set_from_id(id);
owned
}
pub fn new_num<T: Into<Coefficient>>(num: T) -> Atom<P> {
let mut owned = Self::new();
owned.to_num().set_from_coeff(num.into());
owned
}
pub fn printer<'a, 'b>(&'a self, state: &'b State) -> AtomPrinter<'a, 'b, P> {
AtomPrinter::new(self.as_view(), state)
}
#[inline]
pub fn to_num(&mut self) -> &mut P::ON {
let mut ov = std::mem::replace(self, Atom::Empty);
*self = match ov {
Atom::Num(_) => {
ov.reset();
ov
}
Atom::Var(v) => Atom::Num(v.to_owned_num()),
Atom::Fun(f) => Atom::Num(f.to_owned_num()),
Atom::Pow(p) => Atom::Num(p.to_owned_num()),
Atom::Mul(m) => Atom::Num(m.to_owned_num()),
Atom::Add(a) => Atom::Num(a.to_owned_num()),
Atom::Empty => unreachable!(),
};
match self {
Atom::Num(n) => n,
_ => unreachable!(),
}
}
#[inline]
pub fn to_pow(&mut self) -> &mut P::OP {
let mut ov = std::mem::replace(self, Atom::Empty);
*self = match ov {
Atom::Pow(_) => {
ov.reset();
ov
}
Atom::Num(n) => Atom::Pow(n.to_owned_pow()),
Atom::Var(v) => Atom::Pow(v.to_owned_pow()),
Atom::Fun(f) => Atom::Pow(f.to_owned_pow()),
Atom::Mul(m) => Atom::Pow(m.to_owned_pow()),
Atom::Add(a) => Atom::Pow(a.to_owned_pow()),
Atom::Empty => unreachable!(),
};
match self {
Atom::Pow(p) => p,
_ => unreachable!(),
}
}
#[inline]
pub fn to_var(&mut self) -> &mut P::OV {
let mut ov = std::mem::replace(self, Atom::Empty);
*self = match ov {
Atom::Var(_) => {
ov.reset();
ov
}
Atom::Num(n) => Atom::Var(n.to_owned_var()),
Atom::Pow(p) => Atom::Var(p.to_owned_var()),
Atom::Fun(f) => Atom::Var(f.to_owned_var()),
Atom::Mul(m) => Atom::Var(m.to_owned_var()),
Atom::Add(a) => Atom::Var(a.to_owned_var()),
Atom::Empty => unreachable!(),
};
match self {
Atom::Var(v) => v,
_ => unreachable!(),
}
}
#[inline]
pub fn to_fun(&mut self) -> &mut P::OF {
let mut of = std::mem::replace(self, Atom::Empty);
*self = match of {
Atom::Fun(_) => {
of.reset();
of
}
Atom::Num(n) => Atom::Fun(n.to_owned_fun()),
Atom::Pow(p) => Atom::Fun(p.to_owned_fun()),
Atom::Var(v) => Atom::Fun(v.to_owned_fun()),
Atom::Mul(m) => Atom::Fun(m.to_owned_fun()),
Atom::Add(a) => Atom::Fun(a.to_owned_fun()),
Atom::Empty => unreachable!(),
};
match self {
Atom::Fun(f) => f,
_ => unreachable!(),
}
}
#[inline]
pub fn to_mul(&mut self) -> &mut P::OM {
let mut om = std::mem::replace(self, Atom::Empty);
*self = match om {
Atom::Mul(_) => {
om.reset();
om
}
Atom::Num(n) => Atom::Mul(n.to_owned_mul()),
Atom::Pow(p) => Atom::Mul(p.to_owned_mul()),
Atom::Var(v) => Atom::Mul(v.to_owned_mul()),
Atom::Fun(f) => Atom::Mul(f.to_owned_mul()),
Atom::Add(a) => Atom::Mul(a.to_owned_mul()),
Atom::Empty => unreachable!(),
};
match self {
Atom::Mul(m) => m,
_ => unreachable!(),
}
}
#[inline]
pub fn to_add(&mut self) -> &mut P::OA {
let mut oa = std::mem::replace(self, Atom::Empty);
*self = match oa {
Atom::Add(_) => {
oa.reset();
oa
}
Atom::Num(n) => Atom::Add(n.to_owned_add()),
Atom::Pow(p) => Atom::Add(p.to_owned_add()),
Atom::Var(v) => Atom::Add(v.to_owned_add()),
Atom::Fun(f) => Atom::Add(f.to_owned_add()),
Atom::Mul(m) => Atom::Add(m.to_owned_add()),
Atom::Empty => unreachable!(),
};
match self {
Atom::Add(a) => a,
_ => unreachable!(),
}
}
pub fn new_from_view(view: &AtomView<P>) -> Atom<P> {
let mut owned = Atom::new();
owned.set_from_view(view);
owned
}
#[inline(always)]
pub fn set_from_view(&mut self, view: &AtomView<P>) {
match view {
AtomView::Num(n) => {
let num = self.to_num();
num.set_from_view(n);
}
AtomView::Var(v) => {
let var = self.to_var();
var.set_from_view(v);
}
AtomView::Fun(f) => {
let fun = self.to_fun();
fun.set_from_view(f);
}
AtomView::Pow(p) => {
let pow = self.to_pow();
pow.set_from_view(p);
}
AtomView::Mul(m) => {
let mul = self.to_mul();
mul.set_from_view(m);
}
AtomView::Add(a) => {
let add = self.to_add();
add.set_from_view(a);
}
}
}
#[inline(always)]
pub fn as_view(&self) -> AtomView<'_, P> {
match self {
Atom::Num(n) => AtomView::Num(n.to_num_view()),
Atom::Var(v) => AtomView::Var(v.to_var_view()),
Atom::Fun(f) => AtomView::Fun(f.to_fun_view()),
Atom::Pow(p) => AtomView::Pow(p.to_pow_view()),
Atom::Mul(m) => AtomView::Mul(m.to_mul_view()),
Atom::Add(a) => AtomView::Add(a.to_add_view()),
Atom::Empty => unreachable!(),
}
}
}
impl<P: AtomSet> ResettableBuffer for Atom<P> {
fn new() -> Self {
Self::Num(P::ON::new())
}
#[inline(always)]
fn reset(&mut self) {
match self {
Atom::Num(n) => n.reset(),
Atom::Var(v) => v.reset(),
Atom::Fun(f) => f.reset(),
Atom::Pow(p) => p.reset(),
Atom::Mul(m) => m.reset(),
Atom::Add(a) => a.reset(),
Atom::Empty => {}
}
}
}
pub struct FunctionBuilder<'a, P: AtomSet = Linear> {
state: &'a State,
workspace: &'a Workspace<P>,
handle: BufferHandle<'a, Atom<P>>,
}
impl<'a, P: AtomSet> FunctionBuilder<'a, P> {
pub fn new(
name: Identifier,
state: &'a State,
workspace: &'a Workspace<P>,
) -> FunctionBuilder<'a, P> {
let mut a = workspace.new_atom();
let f = a.to_fun();
f.set_from_name(name);
f.set_dirty(true);
FunctionBuilder {
state,
workspace,
handle: a,
}
}
pub fn add_arg<'b, T: AsAtomView<'b, P>>(mut self, arg: T) -> FunctionBuilder<'a, P> {
if let Atom::Fun(f) = self.handle.get_mut() {
f.add_arg(arg.as_atom_view());
}
self
}
pub fn finish(self) -> AtomBuilder<'a, BufferHandle<'a, Atom<P>>, P> {
let mut out = self.workspace.new_atom();
self.handle
.as_view()
.normalize(self.workspace, self.state, &mut out);
AtomBuilder {
state: self.state,
workspace: self.workspace,
out,
}
}
}
pub struct AtomBuilder<'a, A: DerefMut<Target = Atom<P>>, P: AtomSet = Linear> {
state: &'a State,
workspace: &'a Workspace<P>,
out: A,
}
impl<'a, P: AtomSet, A: DerefMut<Target = Atom<P>>> AtomBuilder<'a, A, P> {
pub fn new<'b, T: AsAtomView<'b, P>>(
atom: T,
state: &'a State,
workspace: &'a Workspace<P>,
mut out: A,
) -> AtomBuilder<'a, A, P> {
out.set_from_view(&atom.as_atom_view());
AtomBuilder {
state,
workspace,
out,
}
}
pub fn as_atom_mut(&mut self) -> &mut Atom<P> {
&mut self.out
}
pub fn pow<'b, T: AsAtomView<'b, P>>(mut self, exp: T) -> AtomBuilder<'a, A, P> {
self.out
.as_view()
.pow_no_norm(self.workspace, exp.as_atom_view())
.as_view()
.normalize(self.workspace, self.state, &mut self.out);
self
}
pub fn rpow<'b, T: AsAtomView<'b, P>>(mut self, base: T) -> AtomBuilder<'a, A, P> {
base.as_atom_view()
.pow_no_norm(self.workspace, self.out.as_view())
.as_view()
.normalize(self.workspace, self.state, &mut self.out);
self
}
}
impl<'a, P: AtomSet, A: DerefMut<Target = Atom<P>>> From<&AtomBuilder<'a, A, P>>
for AtomBuilder<'a, BufferHandle<'a, Atom<P>>, P>
{
fn from(value: &AtomBuilder<'a, A, P>) -> Self {
let mut h = value.workspace.new_atom();
h.set_from_view(&value.as_atom_view());
AtomBuilder {
state: value.state,
workspace: value.workspace,
out: h,
}
}
}
impl<'a, P: AtomSet> Clone for AtomBuilder<'a, BufferHandle<'a, Atom<P>>, P> {
fn clone(&self) -> Self {
let mut h = self.workspace.new_atom();
h.set_from_view(&self.as_atom_view());
AtomBuilder {
state: self.state,
workspace: self.workspace,
out: h,
}
}
}
impl<'a, 'b, P: AtomSet, T: AsAtomView<'b, P>, A: DerefMut<Target = Atom<P>>> std::ops::Add<T>
for AtomBuilder<'a, A, P>
{
type Output = AtomBuilder<'a, A, P>;
fn add(mut self, rhs: T) -> Self::Output {
self.out
.as_view()
.add_no_norm(self.workspace, rhs.as_atom_view())
.as_view()
.normalize(self.workspace, self.state, &mut self.out);
self
}
}
impl<'a, 'b, P: AtomSet, T: AsAtomView<'b, P>, A: DerefMut<Target = Atom<P>>> std::ops::Sub<T>
for AtomBuilder<'a, A, P>
{
type Output = AtomBuilder<'a, A, P>;
fn sub(mut self, rhs: T) -> Self::Output {
self.out
.as_view()
.sub_no_norm(self.workspace, rhs.as_atom_view())
.as_view()
.normalize(self.workspace, self.state, &mut self.out);
self
}
}
impl<'a, 'b, P: AtomSet, T: AsAtomView<'b, P>, A: DerefMut<Target = Atom<P>>> std::ops::Mul<T>
for AtomBuilder<'a, A, P>
{
type Output = AtomBuilder<'a, A, P>;
fn mul(mut self, rhs: T) -> Self::Output {
self.out
.as_view()
.mul_no_norm(self.workspace, rhs.as_atom_view())
.as_view()
.normalize(self.workspace, self.state, &mut self.out);
self
}
}
impl<'a, 'b, P: AtomSet, T: AsAtomView<'b, P>, A: DerefMut<Target = Atom<P>>> std::ops::Div<T>
for AtomBuilder<'a, A, P>
{
type Output = AtomBuilder<'a, A, P>;
fn div(mut self, rhs: T) -> Self::Output {
self.out
.as_view()
.div_no_norm(self.workspace, rhs.as_atom_view())
.as_view()
.normalize(self.workspace, self.state, &mut self.out);
self
}
}
impl<'a, P: AtomSet, A: DerefMut<Target = Atom<P>>> std::ops::Neg for AtomBuilder<'a, A, P> {
type Output = AtomBuilder<'a, A, P>;
fn neg(mut self) -> Self::Output {
self.out
.as_view()
.neg_no_norm(self.workspace)
.as_view()
.normalize(self.workspace, self.state, &mut self.out);
self
}
}
impl<'a, 'b, P: AtomSet, A: DerefMut<Target = Atom<P>>> AsAtomView<'b, P>
for &'b AtomBuilder<'a, A, P>
{
fn as_atom_view(self) -> AtomView<'b, P> {
self.out.as_atom_view()
}
}