use crate::dacecore::*;
use crate::*;
use auto_ops::*;
pub use ndarray::linalg::Dot;
use ndarray::prelude::*;
use ndarray::*;
pub use num_traits::{One, Pow, Zero};
use std::{
convert::From,
ffi::CStr,
fmt::{Debug, Display},
hash::{Hash, Hasher},
mem::MaybeUninit,
ops,
os::raw::{c_char, c_uint, c_void},
ptr::null_mut,
str::FromStr,
vec,
};
#[repr(C)]
#[derive(Debug)]
pub struct DA {
pub(crate) len: c_uint,
pub(crate) max: c_uint,
pub(crate) dmonomial: *mut c_void,
}
#[derive(Debug)]
pub struct CompiledDA {
pub(crate) dim: usize,
pub(crate) ac: Vec<f64>,
pub(crate) terms: u32,
pub(crate) _vars: u32,
pub(crate) ord: u32,
}
pub trait Compile {
fn compile(&self) -> CompiledDA;
}
macro_rules! simple_wrap {
($name_wrap:ident, $name_core:ident, $doc:literal) => {
#[doc = $doc]
pub fn $name_wrap(&self) -> DA {
let mut out = Self::new();
unsafe { $name_core(self, &mut out) };
check_exception_panic();
out
}
};
}
impl DA {
pub fn init(ord: u32, nvar: u32) {
if !Self::check_version() {
panic!("Incompatible DACE core version!");
}
unsafe { daceInitialize(ord, nvar) };
check_exception_panic();
*INITIALIZED.write().unwrap() = true;
}
pub fn initialize_thread() {
unsafe { daceInitializeThread() };
check_exception_panic();
}
pub fn cleanup_thread() {
unsafe { daceCleanupThread() };
check_exception_panic();
}
pub fn is_initialized() -> bool {
*INITIALIZED.read().unwrap()
}
pub fn version() -> (i32, i32, i32) {
let mut ver = (0, 0, 0);
unsafe { daceGetVersion(&mut ver.0, &mut ver.1, &mut ver.2) };
ver
}
pub fn check_version() -> bool {
let ver = Self::version();
ver.0 == DACE_MAJOR_VERSION && ver.1 == DACE_MINOR_VERSION
}
pub fn max_order() -> u32 {
unsafe { daceGetMaxOrder() }
}
pub fn set_eps(eps: f64) -> f64 {
unsafe { daceSetEpsilon(eps) }
}
pub fn eps() -> f64 {
unsafe { daceGetEpsilon() }
}
pub fn eps_mac() -> f64 {
unsafe { daceGetMachineEpsilon() }
}
pub fn max_variables() -> u32 {
unsafe { daceGetMaxVariables() }
}
pub fn max_monomials() -> u32 {
unsafe { daceGetMaxMonomials() }
}
pub fn set_truncation_order(ot: impl Into<Option<u32>>) -> u32 {
let ot = ot.into().unwrap_or_else(Self::max_order);
let prev_ot = unsafe { daceSetTruncationOrder(ot) };
check_exception_panic();
prev_ot
}
pub fn truncation_order() -> u32 {
unsafe { daceGetTruncationOrder() }
}
pub fn push_truncation_order(ot: impl Into<Option<u32>>) {
let ot: u32 = ot.into().unwrap_or_else(Self::max_order);
TO_STACK
.lock()
.unwrap()
.push(Self::set_truncation_order(ot));
}
pub fn pop_truncation_order() -> Option<u32> {
Some(Self::set_truncation_order(TO_STACK.lock().unwrap().pop()?))
}
pub fn memdump() {
unsafe { daceMemoryDump() }
}
pub fn new() -> Self {
let mut da = MaybeUninit::<DA>::uninit();
unsafe { daceAllocateDA(da.as_mut_ptr(), 0) };
check_exception_panic();
unsafe { da.assume_init() }
}
pub fn random(cm: f64) -> Self {
let mut out = DA::new();
unsafe { daceCreateRandom(&mut out, cm) };
check_exception_panic();
out
}
pub fn cons(&self) -> f64 {
let out = unsafe { daceGetConstant(self) };
check_exception_panic();
out
}
pub fn linear(&self) -> AlgebraicVector<f64> {
let mut out = AlgebraicVector::zeros(Self::max_variables() as usize);
unsafe { daceGetLinear(self, out.as_mut_ptr()) };
check_exception_panic();
out
}
pub fn gradient(&self) -> AlgebraicVector<DA> {
let nvar = Self::max_variables() as usize;
Array::from_shape_fn((nvar,), |i| self.deriv(i as u32 + 1)).into()
}
pub fn coefficient(&self, jj: &Vec<u32>) -> f64 {
let nvar = Self::max_variables() as usize;
let ptr;
let mut temp;
if jj.len() >= nvar {
ptr = jj.as_ptr();
} else {
temp = jj.clone();
temp.resize(nvar, 0);
ptr = temp.as_ptr();
}
let coeff = unsafe { daceGetCoefficient(self, ptr) };
check_exception_panic();
coeff
}
pub fn set_coefficient(&mut self, jj: &Vec<u32>, coeff: f64) {
let nvar = Self::max_variables() as usize;
let ptr;
let mut temp;
if jj.len() >= nvar {
ptr = jj.as_ptr();
} else {
temp = jj.clone();
temp.resize(nvar, 0);
ptr = temp.as_ptr();
}
unsafe { daceSetCoefficient(self, ptr, coeff) };
check_exception_panic();
}
pub fn multiply_monomials<T: AsRef<Self>>(&self, oth: T) -> Self {
let mut out = Self::new();
unsafe { daceMultiplyMonomials(self, oth.as_ref(), &mut out) };
check_exception_panic();
out
}
pub fn divide(&self, var: u32, p: u32) -> Self {
let mut out = Self::new();
unsafe { daceDivideByVariable(self, var, p, &mut out) };
check_exception_panic();
out
}
pub fn deriv(&self, i: u32) -> Self {
let mut out = Self::new();
unsafe { daceDifferentiate(i, self, &mut out) };
check_exception_panic();
out
}
pub fn integ(&self, i: u32) -> Self {
let mut out = Self::new();
unsafe { daceIntegrate(i, self, &mut out) };
check_exception_panic();
out
}
pub fn trim(&self, imin: u32, imax: impl Into<Option<u32>>) -> Self {
let mut out = Self::new();
let imax = imax.into().unwrap_or_else(Self::max_order);
unsafe { daceTrim(self, imin, imax, &mut out) };
check_exception_panic();
out
}
simple_wrap!{trunc, daceTruncate, "Truncate the constant part of a DA object to an integer."}
simple_wrap!{round, daceRound, "Round the constant part of a DA object to an integer."}
pub fn root(&self, p: i32) -> DA {
let mut out = DA::new();
unsafe { daceRoot(self, p, &mut out) };
check_exception_panic();
out
}
simple_wrap!{sqr, daceSquare, "Compute the square of a DA object."}
#[inline(always)]
pub fn square(&self) -> DA {
self.sqr()
}
simple_wrap!{sqrt, daceSquareRoot, "Compute the square root of a DA object."}
simple_wrap!{isrt, daceInverseSquareRoot, "Compute the inverse square root of a DA object."}
simple_wrap!{cbrt, daceCubicRoot, "Compute the cubic root of a DA object."}
simple_wrap!{icrt, daceInverseCubicRoot, "Compute the inverse cubic root of a DA object."}
pub fn hypot<T: AsRef<DA>>(&self, oth: T) -> DA {
let mut out = DA::new();
unsafe { daceHypotenuse(self, oth.as_ref(), &mut out) };
check_exception_panic();
out
}
simple_wrap!{exp, daceExponential, "Compute the exponential of a DA object."}
simple_wrap!{log, daceLogarithm, "Compute the natural logarithm of a DA object."}
pub fn logb(&self, b: f64) -> DA {
let mut out = DA::new();
unsafe { daceLogarithmBase(self, b, &mut out) };
check_exception_panic();
out
}
simple_wrap!{log10, daceLogarithm10, "Compute the 10 based logarithm of a DA object."}
simple_wrap!{log2, daceLogarithm2, "Compute the 2 based logarithm of a DA object."}
simple_wrap!{sin, daceSine, "Compute the sine of a DA object."}
simple_wrap!{cos, daceCosine, "Compute the cosine of a DA object."}
simple_wrap!{tan, daceTangent, "Compute the tangent of a DA object."}
simple_wrap!{asin, daceArcSine, "Compute the arcsine of a DA object."}
#[inline(always)]
pub fn arcsin(&self) -> Self {
self.asin()
}
simple_wrap!{acos, daceArcCosine, "Compute the arccosine of a DA object."}
#[inline(always)]
pub fn arccos(&self) -> Self {
self.acos()
}
simple_wrap!{atan, daceArcTangent, "Compute the arctangent of a DA object."}
#[inline(always)]
pub fn arctan(&self) -> Self {
self.atan()
}
pub fn atan2<T: AsRef<Self>>(&self, oth: T) -> Self {
let mut out = Self::new();
unsafe { daceArcTangent2(self, oth.as_ref(), &mut out) };
check_exception_panic();
out
}
#[inline(always)]
pub fn arctan2<T: AsRef<Self>>(&self, oth: T) -> Self {
self.atan2(oth)
}
simple_wrap!{sinh, daceHyperbolicSine, "Compute the hyperbolic sine of a DA object."}
simple_wrap!{cosh, daceHyperbolicCosine, "Compute the hyperbolic cosine of a DA object."}
simple_wrap!{tanh, daceHyperbolicTangent, "Compute the hyperbolic tangent of a DA object."}
simple_wrap!{asinh, daceHyperbolicArcSine, "Compute the hyperbolic arcsine of a DA object."}
#[inline(always)]
pub fn arcsinh(&self) -> Self {
self.asinh()
}
simple_wrap!{acosh, daceHyperbolicArcCosine, "Compute the hyperbolic arccosine of a DA object."}
#[inline(always)]
pub fn arccosh(&self) -> Self {
self.acosh()
}
simple_wrap!{atanh, daceHyperbolicArcTangent, "Compute the hyperbolic arctangent of a DA object."}
#[inline(always)]
pub fn arctanh(&self) -> Self {
self.atanh()
}
simple_wrap!{minv, daceMultiplicativeInverse, "Compute the multiplicative inverse of a DA object."}
simple_wrap!{erf, daceErrorFunction, "Compute the error function of a DA object."}
simple_wrap!{erfc, daceComplementaryErrorFunction, "Compute the complementary error function of a DA object."}
pub fn besselj(&self, n: i32) -> Self {
let mut out = Self::new();
unsafe { daceBesselJFunction(self, n, &mut out) };
check_exception_panic();
out
}
pub fn bessely(&self, n: i32) -> Self {
let mut out = Self::new();
unsafe { daceBesselYFunction(self, n, &mut out) };
check_exception_panic();
out
}
pub fn besseli(&self, n: i32, scaled: bool) -> Self {
let mut out = Self::new();
unsafe { daceBesselIFunction(self, n, scaled, &mut out) };
check_exception_panic();
out
}
pub fn besselk(&self, n: i32, scaled: bool) -> Self {
let mut out = Self::new();
unsafe { daceBesselKFunction(self, n, scaled, &mut out) };
check_exception_panic();
out
}
simple_wrap!{gamma, daceGammaFunction, "Compute the Gamma function of a DA object."}
simple_wrap!{loggamma, daceLogGammaFunction, "Compute the Logarithmic Gamma function (i.e. the natural logarithm of Gamma) of a DA object."}
pub fn psi(&self, n: u32) -> Self {
let mut out = Self::new();
unsafe { dacePsiFunction(self, n, &mut out) };
check_exception_panic();
out
}
#[inline]
pub fn size(&self) -> u32 {
self.len
}
pub fn abs(&self) -> f64 {
let out = unsafe { daceAbsoluteValue(self) };
check_exception_panic();
out
}
pub fn norm(&self, type_: u32) -> f64 {
let out = unsafe { daceNorm(self, type_) };
check_exception_panic();
out
}
pub fn order_norm(&self, var: u32, type_: u32) -> AlgebraicVector<f64> {
let mut v = AlgebraicVector::<f64>::zeros(Self::max_order() as usize + 1);
unsafe { daceOrderedNorm(self, var, type_, v.as_mut_ptr()) };
check_exception_panic();
v
}
pub fn estim_norm(&self, var: u32, type_: u32, nc: u32) -> AlgebraicVector<f64> {
let mut v = AlgebraicVector::<f64>::zeros(nc as usize + 1);
unsafe { daceEstimate(self, var, type_, v.as_mut_ptr(), null_mut(), nc) };
check_exception_panic();
v
}
pub fn estim_norm_err(&self, var: u32, type_: u32, nc: u32) -> AlgebraicVector<f64> {
let mut err = AlgebraicVector::<f64>::zeros(nc.min(Self::max_order()) as usize + 1);
let mut v = AlgebraicVector::<f64>::zeros(nc as usize + 1);
unsafe { daceEstimate(self, var, type_, v.as_mut_ptr(), err.as_mut_ptr(), nc) };
check_exception_panic();
v
}
pub fn bound(&self) -> Interval {
let mut out = Interval {
m_lb: 0.0,
m_ub: 0.0,
};
unsafe { daceGetBounds(self, &mut out.m_lb, &mut out.m_ub) };
check_exception_panic();
out
}
pub fn conv_radius(&self, eps: f64, type_: u32) -> f64 {
let ord = Self::truncation_order();
let res = self.estim_norm(0, type_, ord + 1);
(eps / res[ord as usize + 1]).powf(1.0 / (ord + 1) as f64)
}
pub fn plug(&self, var: u32, val: f64) -> DA {
let mut out = DA::new();
unsafe { daceEvalVariable(self, var, val, &mut out) };
check_exception_panic();
out
}
pub fn eval_monomials<T: AsRef<DA>>(&self, values: T) -> f64 {
let out = unsafe { daceEvalMonomials(self, values.as_ref()) };
check_exception_panic();
out
}
pub fn replace_variable(&self, from: u32, to: u32, val: f64) -> DA {
let mut out = DA::new();
unsafe { daceReplaceVariable(self, from, to, val, &mut out) };
check_exception_panic();
out
}
pub fn scale_variable(&self, var: u32, val: f64) -> DA {
let mut out = DA::new();
unsafe { daceScaleVariable(self, var, val, &mut out) };
check_exception_panic();
out
}
pub fn translate_variable(&self, var: u32, a: f64, c: f64) -> DA {
let mut out = DA::new();
unsafe { daceTranslateVariable(self, var, a, c, &mut out) };
check_exception_panic();
out
}
pub fn is_constant(&self) -> bool {
*self == self.cons()
}
pub fn print(&self) {
unsafe { dacePrint(self) };
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut size = 0;
unsafe { daceExportBlob(self, null_mut(), &mut size) };
let mut out = vec![0; size as usize];
unsafe { daceExportBlob(self, out.as_mut_ptr().cast(), &mut size) };
check_exception_panic();
out
}
}
impl AsRef<DA> for DA {
#[inline]
fn as_ref(&self) -> &DA {
self
}
}
impl AsMut<DA> for DA {
#[inline]
fn as_mut(&mut self) -> &mut DA {
self
}
}
pub trait Assign<T> {
fn assign(&mut self, oth: T);
}
impl Assign<(u32, f64)> for DA {
fn assign(&mut self, oth: (u32, f64)) {
unsafe { daceCreateVariable(self, oth.0, oth.1) };
check_exception_panic();
}
}
impl Assign<u32> for DA {
fn assign(&mut self, oth: u32) {
unsafe { daceCreateVariable(self, oth, 1.0) };
check_exception_panic();
}
}
impl Assign<f64> for DA {
fn assign(&mut self, oth: f64) {
unsafe { daceCreateConstant(self, oth) };
check_exception_panic();
}
}
impl Assign<&DA> for DA {
fn assign(&mut self, oth: &DA) {
unsafe { daceCopy(oth, self) };
check_exception_panic();
}
}
impl Assign<DA> for DA {
fn assign(&mut self, mut oth: DA) {
*self = Self {
len: oth.len,
max: oth.max,
dmonomial: oth.dmonomial,
};
unsafe { daceInvalidateDA(&mut oth) };
check_exception_panic();
}
}
impl PartialEq<f64> for DA {
fn eq(&self, other: &f64) -> bool {
(self - *other).size() == 0
}
}
impl PartialEq for DA {
fn eq(&self, other: &Self) -> bool {
(self - other).size() == 0
}
}
impl Eq for DA {}
impl Display for DA {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut nstr = unsafe { daceGetMaxMonomials() } + 2;
let mut vec = vec![0 as c_char; nstr as usize * DACE_STRLEN];
let vec_ptr = vec.as_mut_ptr();
unsafe { daceWrite(self, vec_ptr, &mut nstr) };
for i in 0..nstr {
let ptr = unsafe { vec_ptr.offset((i as usize * DACE_STRLEN) as isize) };
let s = unsafe { CStr::from_ptr(ptr) };
let s = s.to_str().expect("Error decoding string");
writeln!(f, "{s}")?;
}
check_exception_panic();
Ok(())
}
}
impl ScalarOperand for DA {}
impl ScalarOperand for &'static DA {}
impl_op_ex!(+ |a: &DA, b: &DA| -> DA {
let mut c = DA::new();
unsafe { daceAdd(a, b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(+= |a: &mut DA, b: &DA| {
unsafe { daceAdd(a, b, a) };
check_exception_panic();
});
impl_op_ex_commutative!(+ |a: &DA, b: &f64| -> DA {
let mut c = DA::new();
unsafe { daceAddDouble(a, *b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(+= |a: &mut DA, b: &f64| {
unsafe { daceAddDouble(a, *b, a) };
check_exception_panic();
});
impl_op_ex!(-|a: &DA, b: &DA| -> DA {
let mut c = DA::new();
unsafe { daceSubtract(a, b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(-= |a: &mut DA, b: &DA| {
unsafe { daceSubtract(a, b, a) };
check_exception_panic();
});
impl_op_ex!(-|a: &DA, b: &f64| -> DA {
let mut c = DA::new();
unsafe { daceSubtractDouble(a, *b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(-|a: &f64, b: &DA| -> DA {
let mut c = DA::new();
unsafe { daceDoubleSubtract(b, *a, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(-= |a: &mut DA, b: &f64| {
unsafe { daceSubtractDouble(a, *b, a) };
check_exception_panic();
});
impl_op_ex!(*|a: &DA, b: &DA| -> DA {
let mut c = DA::new();
unsafe { daceMultiply(a, b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(*= |a: &mut DA, b: &DA| {
unsafe { daceMultiply(a, b, a) };
check_exception_panic();
});
impl_op_ex_commutative!(*|a: &DA, b: &f64| -> DA {
let mut c = DA::new();
unsafe { daceMultiplyDouble(a, *b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(*= |a: &mut DA, b: &f64| {
unsafe { daceMultiplyDouble(a, *b, a) };
check_exception_panic();
});
impl_op_ex!(/ |a: &DA, b: &DA| -> DA {
let mut c = DA::new();
unsafe { daceDivide(a, b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(/= |a: &mut DA, b: &DA| {
unsafe { daceDivide(a, b, a) };
check_exception_panic();
});
impl_op_ex!(/ |a: &DA, b: &f64| -> DA {
let mut c = DA::new();
unsafe { daceDivideDouble(a, *b, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(/ |a: f64, b: &DA| -> DA {
let mut c = DA::new();
unsafe { daceDoubleDivide(b, a, &mut c) };
check_exception_panic();
c
});
impl_op_ex!(/= |a: &mut DA, b: &f64| {
unsafe { daceDivideDouble(a, *b, a) };
check_exception_panic();
});
impl ops::Neg for DA {
type Output = DA;
fn neg(self) -> Self::Output {
self * -1.0
}
}
impl ops::Neg for &DA {
type Output = DA;
fn neg(self) -> Self::Output {
self * -1.0
}
}
impl ops::Rem<f64> for DA {
type Output = DA;
fn rem(self, rhs: f64) -> Self::Output {
&self % rhs
}
}
impl ops::Rem<f64> for &DA {
type Output = DA;
fn rem(self, rhs: f64) -> Self::Output {
let mut out = DA::new();
unsafe { daceModulo(self, rhs, &mut out) };
check_exception_panic();
out
}
}
impl ops::RemAssign<f64> for DA {
fn rem_assign(&mut self, rhs: f64) {
unsafe { daceModulo(self, rhs, self) };
check_exception_panic();
}
}
impl Pow<i32> for &DA {
type Output = DA;
fn pow(self: Self, p: i32) -> DA {
let mut out = DA::new();
unsafe { dacePower(self, p, &mut out) };
check_exception_panic();
out
}
}
impl Pow<f64> for &DA {
type Output = DA;
fn pow(self: Self, p: f64) -> DA {
let mut out = DA::new();
unsafe { dacePowerDouble(self, p, &mut out) };
check_exception_panic();
out
}
}
impl<T: AsRef<DA>> Pow<T> for &DA {
type Output = DA;
fn pow(self: Self, p: T) -> DA {
let p_ref = p.as_ref();
if p_ref.is_constant() {
return self.pow(p_ref.cons());
}
let mut out = DA::new();
unsafe {
daceLogarithm(self, &mut out);
daceMultiply(p_ref, &out, &mut out);
daceExponential(&out, &mut out);
}
check_exception_panic();
out
}
}
impl From<(u32, f64)> for DA {
fn from(ic: (u32, f64)) -> Self {
let mut out = Self::new();
out.assign(ic);
out
}
}
impl From<u32> for DA {
fn from(i: u32) -> Self {
let mut out = Self::new();
out.assign(i);
out
}
}
impl From<f64> for DA {
fn from(c: f64) -> Self {
let mut out = Self::new();
out.assign(c);
out
}
}
impl From<&DA> for DA {
fn from(oth: &DA) -> Self {
oth.to_owned()
}
}
impl TryFrom<&Vec<u8>> for DA {
type Error = DACEException;
fn try_from(blob: &Vec<u8>) -> Result<Self, DACEException> {
let mut out = Self::new();
unsafe { daceImportBlob(blob.as_ptr().cast(), &mut out) };
check_exception()?;
Ok(out)
}
}
impl FromStr for DA {
type Err = DACEException;
fn from_str(s: &str) -> Result<Self, DACEException> {
let mut out = Self::new();
let nstr = s.lines().count();
let mut vec = vec![0 as c_char; nstr * DACE_STRLEN];
let mut vec_ptr = vec.as_mut_ptr();
unsafe {
for line in s.lines() {
vec_ptr.copy_from(line.as_ptr() as *const c_char, line.len());
vec_ptr = vec_ptr.offset(DACE_STRLEN as isize);
}
daceRead(&mut out, vec.as_ptr(), nstr as c_uint);
}
check_exception()?;
Ok(out)
}
}
impl Clone for DA {
fn clone(&self) -> Self {
let mut out = Self::new();
unsafe { daceCopy(self, &mut out) };
check_exception_panic();
out
}
}
impl Hash for DA {
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_bytes().hash(state);
}
}
impl Drop for DA {
fn drop(&mut self) {
unsafe {
daceFreeDA(self);
if daceGetError() != 0 {
daceClearError();
}
}
}
}
impl Compile for DA {
fn compile(&self) -> CompiledDA {
darray![self.to_owned()].compile()
}
}
impl Default for DA {
fn default() -> Self {
Self::new()
}
}
impl Zero for DA {
fn zero() -> Self {
DA::new()
}
fn is_zero(&self) -> bool {
self.size() == 0
}
fn set_zero(&mut self) {
self.assign(0.0)
}
}
impl One for DA {
fn one() -> Self {
da!(1.0)
}
fn is_one(&self) -> bool
where
Self: PartialEq,
{
*self == 1.0
}
fn set_one(&mut self) {
self.assign(1.0);
}
}
pub trait Eval<Args> {
type Output;
fn eval(&self, args: Args) -> Self::Output;
}
impl Eval<&AlgebraicVector<f64>> for CompiledDA {
type Output = AlgebraicVector<f64>;
fn eval(&self, args: &AlgebraicVector<f64>) -> Self::Output {
let mut res = AlgebraicVector::<f64>::zeros(self.dim);
let narg = args.len();
let mut xm = AlgebraicVector::<f64>::ones(self.ord as usize + 1);
for i in 0..self.dim {
res[i] = self.ac[i + 2];
}
let mut p = 2 + self.dim as usize;
for _ in 1..self.terms {
let jl = self.ac[p] as usize;
p += 1;
let jv = self.ac[p] as usize - 1;
p += 1;
if jv < narg {
xm[jl] = xm[jl - 1] * args[jv];
} else {
xm[jl] = 0.0;
}
for j in 0..self.dim {
res[j] += xm[jl] * self.ac[p];
p += 1;
}
}
res
}
}
impl Eval<&AlgebraicVector<DA>> for CompiledDA {
type Output = AlgebraicVector<DA>;
fn eval(&self, args: &AlgebraicVector<DA>) -> Self::Output {
let mut res = AlgebraicVector::<DA>::zeros(self.dim);
let narg = args.len();
let mut jlskip = self.ord as usize + 1;
let mut p: usize = 2;
let mut xm = AlgebraicVector::<DA>::ones(self.ord as usize + 1);
let mut tmp = DA::new();
for i in 0..self.dim {
res[i].assign(self.ac[p]);
p += 1;
}
for _ in 1..self.terms {
let jl = self.ac[p] as usize;
p += 1;
let jv = self.ac[p] as usize - 1;
p += 1;
if jl > jlskip {
p += self.dim;
continue;
}
if jv >= narg {
jlskip = jl;
p += self.dim;
continue;
}
jlskip = self.ord as usize + 1;
unsafe { daceMultiply(&xm[jl - 1], &args[jv], &mut xm[jl]) };
for j in 0..self.dim {
if self.ac[p] != 0.0 {
unsafe { daceMultiplyDouble(&xm[jl], self.ac[p], &mut tmp) };
res[j] += &tmp;
}
p += 1;
}
}
check_exception_panic();
res
}
}
impl Eval<&AlgebraicVector<f64>> for DA {
type Output = f64;
fn eval(&self, args: &AlgebraicVector<f64>) -> Self::Output {
self.compile().eval(args)[0]
}
}
impl Eval<&AlgebraicVector<f64>> for AlgebraicVector<DA> {
type Output = AlgebraicVector<f64>;
fn eval(&self, args: &AlgebraicVector<f64>) -> Self::Output {
self.compile().eval(args)
}
}
impl Eval<&AlgebraicVector<DA>> for AlgebraicVector<DA> {
type Output = AlgebraicVector<DA>;
fn eval(&self, args: &AlgebraicVector<DA>) -> Self::Output {
self.compile().eval(args)
}
}
impl Eval<&AlgebraicVector<DA>> for DA {
type Output = DA;
fn eval(&self, args: &AlgebraicVector<DA>) -> DA {
let x = self.compile();
CompiledDA::eval(&x, args)[0].to_owned()
}
}
impl Eval<f64> for CompiledDA {
type Output = AlgebraicVector<f64>;
fn eval(&self, arg: f64) -> Self::Output {
self.eval(&darray![arg]).into()
}
}
impl<T: AsRef<DA>> Eval<T> for CompiledDA {
type Output = AlgebraicVector<DA>;
fn eval(&self, arg: T) -> Self::Output {
self.eval(&darray![arg.as_ref().to_owned()]).into()
}
}
impl<T: AsRef<DA>> Eval<T> for AlgebraicVector<DA> {
type Output = AlgebraicVector<DA>;
fn eval(&self, arg: T) -> Self::Output {
self.compile().eval(arg.as_ref())
}
}
impl<T: AsRef<DA>> Eval<T> for DA {
type Output = DA;
fn eval(&self, arg: T) -> Self::Output {
self.compile().eval(arg.as_ref())[0].to_owned()
}
}
impl Eval<f64> for DA {
type Output = f64;
fn eval(&self, arg: f64) -> Self::Output {
self.compile().eval(arg)[0].to_owned()
}
}