[muparser] Remove the optimizer

The optimizer adds a fair amount of complexity in muparser with no
benefit to fish, since fish is not going to use complicated expressions
or cache parsed expressions.
This commit is contained in:
ridiculousfish 2017-11-22 10:48:09 -08:00
parent 85334432ed
commit a7f6105497
6 changed files with 6 additions and 159 deletions

View file

@ -109,7 +109,6 @@ class ParserBase {
void SetThousandsSep(char_type cThousandsSep = 0);
void ResetLocale();
void EnableOptimizer(bool a_bIsOn = true);
void EnableBuiltInOprt(bool a_bIsOn = true);
bool HasBuiltInOprt() const;

View file

@ -95,8 +95,6 @@ class ParserByteCode {
/** \brief The actual rpn storage. */
rpn_type m_vRPN;
bool m_bEnableOptimizer;
void ConstantFolding(ECmdCode a_Oprt);
public:
@ -113,8 +111,6 @@ class ParserByteCode {
void AddFun(generic_fun_type a_pFun, int a_iArgc);
void AddStrFun(generic_fun_type a_pFun, int a_iArgc, int a_iIdx);
void EnableOptimizer(bool bStat);
void Finalize();
void clear();
std::size_t GetMaxStackSize() const;

View file

@ -176,8 +176,6 @@ value_type Help() {
mu::console() << _T( " list var - list parser variables\n");
mu::console() << _T( " list exprvar - list expression variables\n");
mu::console() << _T( " list const - list all numeric parser constants\n");
mu::console() << _T( " opt on - enable optimizer (default)\n");
mu::console() << _T( " opt off - disable optimizer\n");
mu::console() << _T( " locale de - switch to german locale\n");
mu::console() << _T( " locale en - switch to english locale\n");
mu::console() << _T( " locale reset - reset locale\n");
@ -310,14 +308,6 @@ int CheckKeywords(const mu::char_type *a_szLine, mu::Parser &a_Parser) {
} else if (sLine == _T("list var")) {
ListVar(a_Parser);
return 1;
} else if (sLine == _T("opt on")) {
a_Parser.EnableOptimizer(true);
mu::console() << _T("Optimizer enabled\n");
return 1;
} else if (sLine == _T("opt off")) {
a_Parser.EnableOptimizer(false);
mu::console() << _T("Optimizer disabled\n");
return 1;
} else if (sLine == _T("list const")) {
ListConst(a_Parser);
return 1;
@ -382,7 +372,7 @@ void Calc() {
parser.DefineFun(_T("strfun0"), StrFun0);
parser.DefineFun(_T("strfun2"), StrFun2);
parser.DefineFun(_T("ping"), Ping);
parser.DefineFun(_T("rnd"), Rnd); // Add an unoptimizeable function
parser.DefineFun(_T("rnd"), Rnd);
parser.DefineFun(_T("throw"), ThrowAnException);
parser.DefineOprt(_T("add"), Add, 0);

View file

@ -1441,16 +1441,6 @@ void ParserBase::ClearInfixOprt() {
ReInit();
}
//------------------------------------------------------------------------------
/** \brief Enable or disable the formula optimization feature.
\post Resets the parser to string parser mode.
\throw nothrow
*/
void ParserBase::EnableOptimizer(bool a_bIsOn) {
m_vRPN.EnableOptimizer(a_bIsOn);
ReInit();
}
//---------------------------------------------------------------------------
/** \brief Enable the dumping of bytecode and stack content on the console.
\param bDumpCmd Flag to enable dumping of the current bytecode to the console.

View file

@ -39,8 +39,7 @@
namespace mu {
//---------------------------------------------------------------------------
/** \brief Bytecode default constructor. */
ParserByteCode::ParserByteCode()
: m_iStackPos(0), m_iMaxStackSize(0), m_vRPN(), m_bEnableOptimizer(true) {
ParserByteCode::ParserByteCode() : m_iStackPos(0), m_iMaxStackSize(0), m_vRPN() {
m_vRPN.reserve(50);
}
@ -61,9 +60,6 @@ ParserByteCode &ParserByteCode::operator=(const ParserByteCode &a_ByteCode) {
return *this;
}
//---------------------------------------------------------------------------
void ParserByteCode::EnableOptimizer(bool bStat) { m_bEnableOptimizer = bStat; }
//---------------------------------------------------------------------------
/** \brief Copy state of another object to this.
@ -75,7 +71,6 @@ void ParserByteCode::Assign(const ParserByteCode &a_ByteCode) {
m_iStackPos = a_ByteCode.m_iStackPos;
m_vRPN = a_ByteCode.m_vRPN;
m_iMaxStackSize = a_ByteCode.m_iMaxStackSize;
m_bEnableOptimizer = a_ByteCode.m_bEnableOptimizer;
}
//---------------------------------------------------------------------------
@ -203,131 +198,10 @@ void ParserByteCode::ConstantFolding(ECmdCode a_Oprt) {
\sa ParserToken::ECmdCode
*/
void ParserByteCode::AddOp(ECmdCode a_Oprt) {
bool bOptimized = false;
if (m_bEnableOptimizer) {
std::size_t sz = m_vRPN.size();
// Check for foldable constants like:
// cmVAL cmVAL cmADD
// where cmADD can stand fopr any binary operator applied to
// two constant values.
if (sz >= 2 && m_vRPN[sz - 2].Cmd == cmVAL && m_vRPN[sz - 1].Cmd == cmVAL) {
ConstantFolding(a_Oprt);
bOptimized = true;
} else {
switch (a_Oprt) {
case cmPOW:
// Optimization for polynomials of low order
if (m_vRPN[sz - 2].Cmd == cmVAR && m_vRPN[sz - 1].Cmd == cmVAL) {
if (m_vRPN[sz - 1].Val.data2 == 2)
m_vRPN[sz - 2].Cmd = cmVARPOW2;
else if (m_vRPN[sz - 1].Val.data2 == 3)
m_vRPN[sz - 2].Cmd = cmVARPOW3;
else if (m_vRPN[sz - 1].Val.data2 == 4)
m_vRPN[sz - 2].Cmd = cmVARPOW4;
else
break;
m_vRPN.pop_back();
bOptimized = true;
}
break;
case cmSUB:
case cmADD:
// Simple optimization based on pattern recognition for a shitload of different
// bytecode combinations of addition/subtraction
if ((m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAL) ||
(m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVAR) ||
(m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL) ||
(m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAL) ||
(m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAR &&
m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) ||
(m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVARMUL &&
m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) ||
(m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAR &&
m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr) ||
(m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVARMUL &&
m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr)) {
assert((m_vRPN[sz - 2].Val.ptr == NULL && m_vRPN[sz - 1].Val.ptr != NULL) ||
(m_vRPN[sz - 2].Val.ptr != NULL && m_vRPN[sz - 1].Val.ptr == NULL) ||
(m_vRPN[sz - 2].Val.ptr == m_vRPN[sz - 1].Val.ptr));
m_vRPN[sz - 2].Cmd = cmVARMUL;
m_vRPN[sz - 2].Val.ptr =
(value_type *)((long long)(m_vRPN[sz - 2].Val.ptr) |
(long long)(m_vRPN[sz - 1].Val.ptr)); // variable
m_vRPN[sz - 2].Val.data2 +=
((a_Oprt == cmSUB) ? -1 : 1) * m_vRPN[sz - 1].Val.data2; // offset
m_vRPN[sz - 2].Val.data +=
((a_Oprt == cmSUB) ? -1 : 1) * m_vRPN[sz - 1].Val.data; // multiplicand
m_vRPN.pop_back();
bOptimized = true;
}
break;
case cmMUL:
if ((m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAL) ||
(m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVAR)) {
m_vRPN[sz - 2].Cmd = cmVARMUL;
m_vRPN[sz - 2].Val.ptr =
(value_type *)((long long)(m_vRPN[sz - 2].Val.ptr) |
(long long)(m_vRPN[sz - 1].Val.ptr));
m_vRPN[sz - 2].Val.data =
m_vRPN[sz - 2].Val.data2 + m_vRPN[sz - 1].Val.data2;
m_vRPN[sz - 2].Val.data2 = 0;
m_vRPN.pop_back();
bOptimized = true;
} else if ((m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL) ||
(m_vRPN[sz - 1].Cmd == cmVARMUL && m_vRPN[sz - 2].Cmd == cmVAL)) {
// Optimization: 2*(3*b+1) or (3*b+1)*2 -> 6*b+2
m_vRPN[sz - 2].Cmd = cmVARMUL;
m_vRPN[sz - 2].Val.ptr =
(value_type *)((long long)(m_vRPN[sz - 2].Val.ptr) |
(long long)(m_vRPN[sz - 1].Val.ptr));
if (m_vRPN[sz - 1].Cmd == cmVAL) {
m_vRPN[sz - 2].Val.data *= m_vRPN[sz - 1].Val.data2;
m_vRPN[sz - 2].Val.data2 *= m_vRPN[sz - 1].Val.data2;
} else {
m_vRPN[sz - 2].Val.data =
m_vRPN[sz - 1].Val.data * m_vRPN[sz - 2].Val.data2;
m_vRPN[sz - 2].Val.data2 =
m_vRPN[sz - 1].Val.data2 * m_vRPN[sz - 2].Val.data2;
}
m_vRPN.pop_back();
bOptimized = true;
} else if (m_vRPN[sz - 1].Cmd == cmVAR && m_vRPN[sz - 2].Cmd == cmVAR &&
m_vRPN[sz - 1].Val.ptr == m_vRPN[sz - 2].Val.ptr) {
// Optimization: a*a -> a^2
m_vRPN[sz - 2].Cmd = cmVARPOW2;
m_vRPN.pop_back();
bOptimized = true;
}
break;
case cmDIV:
if (m_vRPN[sz - 1].Cmd == cmVAL && m_vRPN[sz - 2].Cmd == cmVARMUL &&
m_vRPN[sz - 1].Val.data2 != 0) {
// Optimization: 4*a/2 -> 2*a
m_vRPN[sz - 2].Val.data /= m_vRPN[sz - 1].Val.data2;
m_vRPN[sz - 2].Val.data2 /= m_vRPN[sz - 1].Val.data2;
m_vRPN.pop_back();
bOptimized = true;
}
break;
} // switch a_Oprt
}
}
// If optimization can't be applied just write the value
if (!bOptimized) {
--m_iStackPos;
SToken tok;
tok.Cmd = a_Oprt;
m_vRPN.push_back(tok);
}
--m_iStackPos;
SToken tok;
tok.Cmd = a_Oprt;
m_vRPN.push_back(tok);
}
//---------------------------------------------------------------------------

View file

@ -1253,10 +1253,8 @@ int ParserTester::EqnTest(const string_type &a_str, double a_fRes, bool a_fPass)
fVal[2] = p2.Eval();
// Test assignment operator
// additionally disable Optimizer this time
mu::Parser p3;
p3 = p2;
p3.EnableOptimizer(false);
fVal[3] = p3.Eval();
// Test Eval function for multiple return values