Files
IFEM/3rdparty/expreval/func.cpp
Arne Morten Kvarving 327a855d1b expreval: make all classes a template over a scalar
instance for double and autodiff::Variable<double>
2023-10-11 08:52:55 +02:00

1776 lines
44 KiB
C++

// File: func.cpp
// Author: Brian Allen Vanderburg II
// Purpose: ExprEval internal functions
//------------------------------------------------------------------------------
// Includes
#include <new>
#include <memory>
#include <cmath>
#include <cerrno>
#include <ctime>
#include "autodiff/reverse/var/var.hpp"
#include "defs.h"
#include "funclist.h"
#include "node.h"
#include "except.h"
using namespace ExprEval;
// Anonymous namespace for items
namespace
{
// Absolute value
//--------------------------------------------------------------------------
template<class Value>
class abs_FunctionNode : public FunctionNode<Value>
{
public:
explicit abs_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
if constexpr (std::is_same_v<Value, Real>)
return fabs(this->m_nodes[0]->Evaluate());
else
return abs(this->m_nodes[0]->Evaluate());
}
};
template<class Value>
class abs_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "abs";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new abs_FunctionNode<Value>(expr);
}
};
// Modulus
//--------------------------------------------------------------------------
template<class Value>
class mod_FunctionNode : public FunctionNode<Value>
{
public:
explicit mod_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = fmod(this->m_nodes[0]->Evaluate(),
this->m_nodes[1]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class mod_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "mod";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new mod_FunctionNode<Value>(expr);
}
};
// Integer part
//--------------------------------------------------------------------------
template<class Value>
class ipart_FunctionNode : public FunctionNode<Value>
{
public:
explicit ipart_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
Value result;
modf(this->m_nodes[0]->Evaluate(), &result);
return result;
}
};
template<class Value>
class ipart_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "ipart";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new ipart_FunctionNode<Value>(expr);
}
};
// Fraction part
//--------------------------------------------------------------------------
template<class Value>
class fpart_FunctionNode : public FunctionNode<Value>
{
public:
explicit fpart_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
Value dummy;
return modf(this->m_nodes[0]->Evaluate(), &dummy);
}
};
template<class Value>
class fpart_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "fpart";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new fpart_FunctionNode<Value>(expr);
}
};
// Minimum
//--------------------------------------------------------------------------
template<class Value>
class min_FunctionNode : public FunctionNode<Value>
{
public:
explicit min_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, -1, 0, 0);
}
Value DoEvaluate() override
{
Value result = 0;
size_t pos = 0;
for (const auto& node : this->m_nodes) {
Value tmp = node->Evaluate();
if (pos == 0 || tmp < result)
result = tmp;
++pos;
}
return result;
}
};
template<class Value>
class min_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "min";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new min_FunctionNode<Value>(expr);
}
};
// Maximum
//--------------------------------------------------------------------------
template<class Value>
class max_FunctionNode : public FunctionNode<Value>
{
public:
explicit max_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, -1, 0, 0);
}
Value DoEvaluate() override
{
Value result = 0;
size_t pos = 0;
for (const auto& node : this->m_nodes)
{
Value tmp = node->Evaluate();
if (pos == 0 || tmp > result)
result = tmp;
++pos;
}
return result;
}
};
template<class Value>
class max_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "max";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new max_FunctionNode<Value>(expr);
}
};
// Square root
//--------------------------------------------------------------------------
template<class Value>
class sqrt_FunctionNode : public FunctionNode<Value>
{
public:
explicit sqrt_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = sqrt(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class sqrt_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "sqrt";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new sqrt_FunctionNode<Value>(expr);
}
};
// Sine
//--------------------------------------------------------------------------
template<class Value>
class sin_FunctionNode : public FunctionNode<Value>
{
public:
explicit sin_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = sin(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class sin_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "sin";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new sin_FunctionNode<Value>(expr);
}
};
// Cosine
//--------------------------------------------------------------------------
template<class Value>
class cos_FunctionNode : public FunctionNode<Value>
{
public:
explicit cos_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = cos(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class cos_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "cos";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new cos_FunctionNode<Value>(expr);
}
};
// Tangent
//--------------------------------------------------------------------------
template<class Value>
class tan_FunctionNode : public FunctionNode<Value>
{
public:
explicit tan_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = tan(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class tan_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "tan";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new tan_FunctionNode<Value>(expr);
}
};
// Hyperbolic Sine
//--------------------------------------------------------------------------
template<class Value>
class sinh_FunctionNode : public FunctionNode<Value>
{
public:
explicit sinh_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
auto result = sinh(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class sinh_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "sinh";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new sinh_FunctionNode<Value>(expr);
}
};
// Hyperbolic Cosine
//--------------------------------------------------------------------------
template<class Value>
class cosh_FunctionNode : public FunctionNode<Value>
{
public:
explicit cosh_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = cosh(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class cosh_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "cosh";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new cosh_FunctionNode<Value>(expr);
}
};
// Hyperbolic Tangent
//--------------------------------------------------------------------------
template<class Value>
class tanh_FunctionNode : public FunctionNode<Value>
{
public:
explicit tanh_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = tanh(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class tanh_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "tanh";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new tanh_FunctionNode<Value>(expr);
}
};
// Arc Sine
//--------------------------------------------------------------------------
template<class Value>
class asin_FunctionNode : public FunctionNode<Value>
{
public:
explicit asin_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = asin(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class asin_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "asin";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new asin_FunctionNode<Value>(expr);
}
};
// Arc Cosine
//--------------------------------------------------------------------------
template<class Value>
class acos_FunctionNode : public FunctionNode<Value>
{
public:
explicit acos_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = acos(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class acos_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "acos";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new acos_FunctionNode<Value>(expr);
}
};
// Arc Tangent
//--------------------------------------------------------------------------
template<class Value>
class atan_FunctionNode : public FunctionNode<Value>
{
public:
explicit atan_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = atan(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class atan_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "atan";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new atan_FunctionNode<Value>(expr);
}
};
// Arc Tangent 2: atan2(y, x)
//--------------------------------------------------------------------------
template<class Value>
class atan2_FunctionNode : public FunctionNode<Value>
{
public:
explicit atan2_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = atan2(this->m_nodes[0]->Evaluate(), this->m_nodes[1]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class atan2_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "atan2";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new atan2_FunctionNode<Value>(expr);
}
};
// Log
//--------------------------------------------------------------------------
template<class Value>
class log_FunctionNode : public FunctionNode<Value>
{
public:
explicit log_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = log10(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class log_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "log";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new log_FunctionNode<Value>(expr);
}
};
// Ln
//--------------------------------------------------------------------------
template<class Value>
class ln_FunctionNode : public FunctionNode<Value>
{
public:
explicit ln_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = log(this->m_nodes[0]->Evaluate());
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class ln_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "ln";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new ln_FunctionNode<Value>(expr);
}
};
// Exp
//--------------------------------------------------------------------------
template<class Value>
class exp_FunctionNode : public FunctionNode<Value>
{
public:
explicit exp_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value x = this->m_nodes[0]->Evaluate();
Value result = exp(x);
if (errno && x > Value(0.0)) // Fixed: No exception on underflow
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class exp_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "exp";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new exp_FunctionNode<Value>(expr);
}
};
// Logn
//--------------------------------------------------------------------------
template<class Value>
class logn_FunctionNode : public FunctionNode<Value>
{
public:
explicit logn_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
// Check for division by zero
Value tmp = log(this->m_nodes[1]->Evaluate());
if(tmp == 0.0)
throw(MathException(this->GetName()));
// Calculate result
Value result = log(this->m_nodes[0]->Evaluate()) / tmp;
if(errno)
throw(MathException(this->GetName()));
return result;
}
};
template<class Value>
class logn_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "logn";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new logn_FunctionNode<Value>(expr);
}
};
template<class Value>
class pow_FunctionNode : public FunctionNode<Value>
{
public:
explicit pow_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
errno = 0;
Value result = pow(this->m_nodes[0]->Evaluate(), this->m_nodes[1]->Evaluate());
if constexpr (std::is_same_v<Value, double>) { // disable exception with autodiff
if(errno)
throw(MathException(this->GetName()));
}
return result;
}
};
template<class Value>
class pow_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "pow";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new pow_FunctionNode<Value>(expr);
}
};
// Ceil
//--------------------------------------------------------------------------
template<class Value>
class ceil_FunctionNode : public FunctionNode<Value>
{
public:
explicit ceil_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
return ceil(this->m_nodes[0]->Evaluate());
}
};
template<class Value>
class ceil_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "ceil";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new ceil_FunctionNode<Value>(expr);
}
};
// Floor
//--------------------------------------------------------------------------
template<class Value>
class floor_FunctionNode : public FunctionNode<Value>
{
public:
explicit floor_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
return floor(this->m_nodes[0]->Evaluate());
}
};
template<class Value>
class floor_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "floor";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new floor_FunctionNode<Value>(expr);
}
};
// Rand
//--------------------------------------------------------------------------
// Get next random (0,1)
inline double NextRandom(double *seed)
{
long a = (long)(*seed) * 214013L + 2531011L;
*seed = (double)a;
return (double)((a >> 16) & 0x7FFF) / 32767.0;
}
template<class Value>
class rand_FunctionNode : public FunctionNode<Value>
{
public:
explicit rand_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(0, 0, 1, 1);
}
Value DoEvaluate() override
{
return NextRandom(this->m_refs[0]);
}
};
template<class Value>
class rand_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "rand";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new rand_FunctionNode<Value>(expr);
}
};
// Random
//--------------------------------------------------------------------------
template<class Value>
class random_FunctionNode : public FunctionNode<Value>
{
public:
explicit random_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 1, 1);
}
Value DoEvaluate() override
{
Value a = this->m_nodes[0]->Evaluate();
Value b = this->m_nodes[1]->Evaluate();
return NextRandom(this->m_refs[0]) * (b - a) + a;
}
};
template<class Value>
class random_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "random";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new random_FunctionNode<Value>(expr);
}
};
// Randomize
//--------------------------------------------------------------------------
template<class Value>
class randomize_FunctionNode : public FunctionNode<Value>
{
public:
explicit randomize_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(0, 0, 1, 1);
}
Value DoEvaluate() override
{
static long curcall = 1;
*this->m_refs[0] = (Value)(((clock() + 1024u + curcall) * time(NULL)) % 2176971487u);
curcall++;
return 0.0;
}
};
template<class Value>
class randomize_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "randomize";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new randomize_FunctionNode<Value>(expr);
}
};
// Radians to degrees
//--------------------------------------------------------------------------
template<class Value>
class deg_FunctionNode : public FunctionNode<Value>
{
public:
explicit deg_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
return (this->m_nodes[0]->Evaluate() * 180.0) / M_PI;
}
};
template<class Value>
class deg_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "deg";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new deg_FunctionNode<Value>(expr);
}
};
// Degrees to radians
//--------------------------------------------------------------------------
template<class Value>
class rad_FunctionNode : public FunctionNode<Value>
{
public:
explicit rad_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
return (this->m_nodes[0]->Evaluate() * M_PI) / 180.0;
}
};
template<class Value>
class rad_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "rad";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new rad_FunctionNode<Value>(expr);
}
};
// Rectangular to polar: rect2pol(x, y, &distance, &angle)
//--------------------------------------------------------------------------
template<class Value>
class rect2pol_FunctionNode : public FunctionNode<Value>
{
public:
explicit rect2pol_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 2, 2);
}
Value DoEvaluate() override
{
errno = 0;
Value x = this->m_nodes[0]->Evaluate();
Value y = this->m_nodes[1]->Evaluate();
Value d = hypot(x, y);
Value a = atan2(y, x);
if(errno)
throw(MathException(this->GetName()));
*this->m_refs[0] = d;
if(a < 0.0)
*this->m_refs[1] = a + (2.0 * M_PI);
else
*this->m_refs[1] = a;
return d;
}
};
template<class Value>
class rect2pol_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "rect2pol";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new rect2pol_FunctionNode<Value>(expr);
}
};
// Polar to rectangular: pol2rect(distance, angle, &x, &y)
//--------------------------------------------------------------------------
template<class Value>
class pol2rect_FunctionNode : public FunctionNode<Value>
{
public:
explicit pol2rect_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 2, 2);
}
Value DoEvaluate() override
{
errno = 0;
Value d = this->m_nodes[0]->Evaluate();
Value a = this->m_nodes[1]->Evaluate();
Value x = d * cos(a);
Value y = d * sin(a);
if(errno)
throw(MathException(this->GetName()));
*this->m_refs[0] = x;
*this->m_refs[1] = y;
return x;
}
};
template<class Value>
class pol2rect_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "pol2rect";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new pol2rect_FunctionNode<Value>(expr);
}
};
// If
//--------------------------------------------------------------------------
template<class Value>
class if_FunctionNode : public FunctionNode<Value>
{
public:
explicit if_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(3, 3, 0, 0);
}
Value DoEvaluate() override
{
Value c = this->m_nodes[0]->Evaluate();
if(c == 0.0)
return this->m_nodes[2]->Evaluate();
else
return this->m_nodes[1]->Evaluate();
}
};
template<class Value>
class if_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "if";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new if_FunctionNode<Value>(expr);
}
};
// Select
//--------------------------------------------------------------------------
template<class Value>
class select_FunctionNode : public FunctionNode<Value>
{
public:
explicit select_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(3, 4, 0, 0);
}
Value DoEvaluate() override
{
Value c = this->m_nodes[0]->Evaluate();
if(c < 0.0)
return this->m_nodes[1]->Evaluate();
else if(c == 0.0)
return this->m_nodes[2]->Evaluate();
else
{
if(this->m_nodes.size() == 3)
return this->m_nodes[2]->Evaluate();
else
return this->m_nodes[3]->Evaluate();
}
}
};
template<class Value>
class select_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "select";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new select_FunctionNode<Value>(expr);
}
};
// Equal
//--------------------------------------------------------------------------
template<class Value>
class equal_FunctionNode : public FunctionNode<Value>
{
public:
explicit equal_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
if(this->m_nodes[0]->Evaluate() == this->m_nodes[1]->Evaluate())
return 1.0;
else
return 0.0;
}
};
template<class Value>
class equal_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "equal";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new equal_FunctionNode<Value>(expr);
}
};
// Above
//--------------------------------------------------------------------------
template<class Value>
class above_FunctionNode : public FunctionNode<Value>
{
public:
explicit above_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
if(this->m_nodes[0]->Evaluate() > this->m_nodes[1]->Evaluate())
return 1.0;
else
return 0.0;
}
};
template<class Value>
class above_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "above";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new above_FunctionNode<Value>(expr);
}
};
// Below
//--------------------------------------------------------------------------
template<class Value>
class below_FunctionNode : public FunctionNode<Value>
{
public:
explicit below_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
if(this->m_nodes[0]->Evaluate() < this->m_nodes[1]->Evaluate())
return 1.0;
else
return 0.0;
}
};
template<class Value>
class below_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "below";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new below_FunctionNode<Value>(expr);
}
};
// Clip
//--------------------------------------------------------------------------
template<class Value>
class clip_FunctionNode : public FunctionNode<Value>
{
public:
explicit clip_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(3, 3, 0, 0);
}
Value DoEvaluate() override
{
Value v = this->m_nodes[0]->Evaluate();
Value a = this->m_nodes[1]->Evaluate();
Value b = this->m_nodes[2]->Evaluate();
if(v < a)
return a;
else if(v > b)
return b;
else
return v;
}
};
template<class Value>
class clip_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "clip";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new clip_FunctionNode<Value>(expr);
}
};
// Clamp
//--------------------------------------------------------------------------
template<class Value>
class clamp_FunctionNode : public FunctionNode<Value>
{
public:
explicit clamp_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(3, 3, 0, 0);
}
Value DoEvaluate() override
{
Value v = this->m_nodes[0]->Evaluate();
Value a = this->m_nodes[1]->Evaluate();
Value b = this->m_nodes[2]->Evaluate();
if(a == b)
return a;
else
{
Value tmp = fmod(v - a, b - a);
if(tmp < 0)
return tmp + b;
else
return tmp + a;
}
}
};
template<class Value>
class clamp_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "clamp";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new clamp_FunctionNode<Value>(expr);
}
};
// Rescale
//--------------------------------------------------------------------------
template<class Value>
class rescale_FunctionNode : public FunctionNode<Value>
{
public:
explicit rescale_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(5, 5, 0, 0);
}
Value DoEvaluate() override
{
Value pnt = this->m_nodes[0]->Evaluate();
Value o1 = this->m_nodes[1]->Evaluate();
Value o2 = this->m_nodes[2]->Evaluate();
Value n1 = this->m_nodes[3]->Evaluate();
Value n2 = this->m_nodes[4]->Evaluate();
Value odiff = o2 - o1;
if(odiff == 0.0)
return n1;
else
{
return (pnt - o1) * (n2 - n1) / odiff + n1;
}
}
};
template<class Value>
class rescale_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "rescale";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new rescale_FunctionNode<Value>(expr);
}
};
// Poly: poly(x, c3, c2, c1, c0): c3*x^3 + c2*x^2 + c1*x + c0
//--------------------------------------------------------------------------
template<class Value>
class poly_FunctionNode : public FunctionNode<Value>
{
public:
explicit poly_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, -1, 0, 0);
}
Value DoEvaluate() override
{
Value total = 0.0;
double curpow;
curpow = (double)(this->m_nodes.size() - 2);
// Value of x
Value x = this->m_nodes[0]->Evaluate();
errno = 0;
for (const auto& node : this->m_nodes)
{
total += node->Evaluate() * pow(x, curpow);
curpow -= 1.0;
}
if(errno)
throw(MathException(this->GetName()));
return total;
}
};
template<class Value>
class poly_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "poly";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new poly_FunctionNode<Value>(expr);
}
};
// And
//--------------------------------------------------------------------------
template<class Value>
class and_FunctionNode : public FunctionNode<Value>
{
public:
explicit and_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
if(this->m_nodes[0]->Evaluate() == 0.0 || this->m_nodes[1]->Evaluate() == 0.0)
return 0.0;
else
return 1.0;
}
};
template<class Value>
class and_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "and";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new and_FunctionNode<Value>(expr);
}
};
// Or
//--------------------------------------------------------------------------
template<class Value>
class or_FunctionNode : public FunctionNode<Value>
{
public:
explicit or_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(2, 2, 0, 0);
}
Value DoEvaluate() override
{
if(this->m_nodes[0]->Evaluate() == 0.0 && this->m_nodes[1]->Evaluate() == 0.0)
return 0.0;
else
return 1.0;
}
};
template<class Value>
class or_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "or";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new or_FunctionNode<Value>(expr);
}
};
// Not
//--------------------------------------------------------------------------
template<class Value>
class not_FunctionNode : public FunctionNode<Value>
{
public:
explicit not_FunctionNode(Expression<Value> *expr) : FunctionNode<Value>(expr)
{
this->SetArgumentCount(1, 1, 0, 0);
}
Value DoEvaluate() override
{
if(this->m_nodes[0]->Evaluate() == 0.0)
return 1.0;
else
return 0.0;
}
};
template<class Value>
class not_FunctionFactory : public FunctionFactory<Value>
{
public:
std::string GetName() const override
{
return "not";
}
FunctionNode<Value> *DoCreate(Expression<Value> *expr) override
{
return new not_FunctionNode<Value>(expr);
}
};
} // namespace
// Initialize default functions
template<class Value>
void FunctionList<Value>::AddDefaultFunctions()
{
#define ADDFUNCTION(name) \
aptr(FunctionFactory<Value>) name ## _func(new name ## _FunctionFactory<Value>()); \
m_functions.push_back(name ## _func.get()); \
name ## _func.release();
ADDFUNCTION(abs);
ADDFUNCTION(sqrt);
ADDFUNCTION(sin);
ADDFUNCTION(cos);
ADDFUNCTION(tan);
ADDFUNCTION(sinh);
ADDFUNCTION(cosh);
ADDFUNCTION(tanh);
ADDFUNCTION(asin);
ADDFUNCTION(acos);
ADDFUNCTION(atan);
ADDFUNCTION(atan2);
ADDFUNCTION(log);
ADDFUNCTION(ln);
ADDFUNCTION(exp);
ADDFUNCTION(logn);
ADDFUNCTION(pow);
ADDFUNCTION(deg);
ADDFUNCTION(rad);
ADDFUNCTION(rect2pol);
ADDFUNCTION(pol2rect);
ADDFUNCTION(if); // Preprocess will take care of this beforehand
ADDFUNCTION(select);
ADDFUNCTION(equal);
ADDFUNCTION(above);
ADDFUNCTION(below);
ADDFUNCTION(clip);
ADDFUNCTION(rescale);
ADDFUNCTION(poly);
ADDFUNCTION(and);
ADDFUNCTION(or);
ADDFUNCTION(not);
if constexpr (std::is_same_v<Value,double>) {
ADDFUNCTION(mod);
ADDFUNCTION(ipart);
ADDFUNCTION(fpart);
ADDFUNCTION(min);
ADDFUNCTION(max);
ADDFUNCTION(ceil);
ADDFUNCTION(floor);
ADDFUNCTION(rand);
ADDFUNCTION(random);
ADDFUNCTION(randomize);
ADDFUNCTION(clamp);
}
}
namespace ExprEval {
template void FunctionList<double>::AddDefaultFunctions();
template class FunctionList<autodiff::var>;
}