summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/plib/pfunction.cpp
diff options
context:
space:
mode:
author couriersud <couriersud@gmx.org>2019-10-31 21:53:50 +0100
committer couriersud <couriersud@gmx.org>2019-10-31 21:53:50 +0100
commitc6b281685d16c02b83b1b0c89acae392ecf851ff (patch)
tree2cd979f919b39e1feeffbde0b22462db59a6492a /src/lib/netlist/plib/pfunction.cpp
parent6c075e602cf83b379b8fa2c981694134b679a538 (diff)
netlist: Compile with float/double floating point. [Couriersud]
Added ability to compile using float instead of double. Specifically the the solver as well as the infrastructure now can have their own floating point type. Currently this is only an academic exercise since numerically demanding circuits like kidniki only work with double/double support. Using float here is pushing numerical stability over the limits. The long term design goal is too have the matrix type (double/float) being a parameter.
Diffstat (limited to 'src/lib/netlist/plib/pfunction.cpp')
-rw-r--r--src/lib/netlist/plib/pfunction.cpp350
1 files changed, 179 insertions, 171 deletions
diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp
index e4ea2d57163..44254706636 100644
--- a/src/lib/netlist/plib/pfunction.cpp
+++ b/src/lib/netlist/plib/pfunction.cpp
@@ -16,207 +16,215 @@
namespace plib {
-void pfunction::compile(const std::vector<pstring> &inputs, const pstring &expr)
-{
- if (plib::startsWith(expr, "rpn:"))
- compile_postfix(inputs, expr.substr(4));
- else
- compile_infix(inputs, expr);
-}
-
-void pfunction::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr)
-{
- std::vector<pstring> cmds(plib::psplit(expr, " "));
- compile_postfix(inputs, cmds, expr);
-}
-
-void pfunction::compile_postfix(const std::vector<pstring> &inputs,
- const std::vector<pstring> &cmds, const pstring &expr)
-{
- m_precompiled.clear();
- int stk = 0;
-
- for (const pstring &cmd : cmds)
+ template <typename NT>
+ void pfunction<NT>::compile(const std::vector<pstring> &inputs, const pstring &expr)
{
- rpn_inst rc;
- if (cmd == "+")
- { rc.m_cmd = ADD; stk -= 1; }
- else if (cmd == "-")
- { rc.m_cmd = SUB; stk -= 1; }
- else if (cmd == "*")
- { rc.m_cmd = MULT; stk -= 1; }
- else if (cmd == "/")
- { rc.m_cmd = DIV; stk -= 1; }
- else if (cmd == "pow")
- { rc.m_cmd = POW; stk -= 1; }
- else if (cmd == "sin")
- { rc.m_cmd = SIN; stk -= 0; }
- else if (cmd == "cos")
- { rc.m_cmd = COS; stk -= 0; }
- else if (cmd == "trunc")
- { rc.m_cmd = TRUNC; stk -= 0; }
- else if (cmd == "rand")
- { rc.m_cmd = RAND; stk += 1; }
+ if (plib::startsWith(expr, "rpn:"))
+ compile_postfix(inputs, expr.substr(4));
else
+ compile_infix(inputs, expr);
+ }
+
+ template <typename NT>
+ void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr)
+ {
+ std::vector<pstring> cmds(plib::psplit(expr, " "));
+ compile_postfix(inputs, cmds, expr);
+ }
+
+ template <typename NT>
+ void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs,
+ const std::vector<pstring> &cmds, const pstring &expr)
+ {
+ m_precompiled.clear();
+ int stk = 0;
+
+ for (const pstring &cmd : cmds)
{
- for (std::size_t i = 0; i < inputs.size(); i++)
+ rpn_inst rc;
+ if (cmd == "+")
+ { rc.m_cmd = ADD; stk -= 1; }
+ else if (cmd == "-")
+ { rc.m_cmd = SUB; stk -= 1; }
+ else if (cmd == "*")
+ { rc.m_cmd = MULT; stk -= 1; }
+ else if (cmd == "/")
+ { rc.m_cmd = DIV; stk -= 1; }
+ else if (cmd == "pow")
+ { rc.m_cmd = POW; stk -= 1; }
+ else if (cmd == "sin")
+ { rc.m_cmd = SIN; stk -= 0; }
+ else if (cmd == "cos")
+ { rc.m_cmd = COS; stk -= 0; }
+ else if (cmd == "trunc")
+ { rc.m_cmd = TRUNC; stk -= 0; }
+ else if (cmd == "rand")
+ { rc.m_cmd = RAND; stk += 1; }
+ else
{
- if (inputs[i] == cmd)
+ for (std::size_t i = 0; i < inputs.size(); i++)
+ {
+ if (inputs[i] == cmd)
+ {
+ rc.m_cmd = PUSH_INPUT;
+ rc.m_param = static_cast<double>(i);
+ stk += 1;
+ break;
+ }
+ }
+ if (rc.m_cmd != PUSH_INPUT)
{
- rc.m_cmd = PUSH_INPUT;
- rc.m_param = static_cast<double>(i);
+ rc.m_cmd = PUSH_CONST;
+ bool err(false);
+ rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err);
+ if (err)
+ throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
stk += 1;
- break;
}
}
- if (rc.m_cmd != PUSH_INPUT)
- {
- rc.m_cmd = PUSH_CONST;
- bool err(false);
- rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err);
- if (err)
- throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
- stk += 1;
- }
+ if (stk < 1)
+ throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
+ m_precompiled.push_back(rc);
}
- if (stk < 1)
- throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
- m_precompiled.push_back(rc);
+ if (stk != 1)
+ throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr));
}
- if (stk != 1)
- throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr));
-}
-
-static int get_prio(const pstring &v)
-{
- if (v == "(" || v == ")")
- return 1;
- else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z")
- return 0;
- else if (v == "*" || v == "/")
- return 20;
- else if (v == "+" || v == "-")
- return 10;
- else if (v == "^")
- return 30;
- else
- return -1;
-}
-
-static pstring pop_check(std::stack<pstring> &stk, const pstring &expr)
-{
- if (stk.size() == 0)
- throw plib::pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr));
- pstring res = stk.top();
- stk.pop();
- return res;
-}
-
-void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring &expr)
-{
- // Shunting-yard infix parsing
- std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"};
- std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep));
- std::stack<pstring> opstk;
- std::vector<pstring> postfix;
-
- for (std::size_t i = 0; i < sexpr.size(); i++)
+
+ static int get_prio(const pstring &v)
{
- pstring &s = sexpr[i];
- if (s=="(")
- opstk.push(s);
- else if (s==")")
- {
- pstring x = pop_check(opstk, expr);
- while (x != "(")
- {
- postfix.push_back(x);
- x = pop_check(opstk, expr);
- }
- if (opstk.size() > 0 && get_prio(opstk.top()) == 0)
- postfix.push_back(pop_check(opstk, expr));
- }
- else if (s==",")
+ if (v == "(" || v == ")")
+ return 1;
+ else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z")
+ return 0;
+ else if (v == "*" || v == "/")
+ return 20;
+ else if (v == "+" || v == "-")
+ return 10;
+ else if (v == "^")
+ return 30;
+ else
+ return -1;
+ }
+
+ static pstring pop_check(std::stack<pstring> &stk, const pstring &expr)
+ {
+ if (stk.size() == 0)
+ throw plib::pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr));
+ pstring res = stk.top();
+ stk.pop();
+ return res;
+ }
+
+ template <typename NT>
+ void pfunction<NT>::compile_infix(const std::vector<pstring> &inputs, const pstring &expr)
+ {
+ // Shunting-yard infix parsing
+ std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"};
+ std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep));
+ std::stack<pstring> opstk;
+ std::vector<pstring> postfix;
+
+ for (std::size_t i = 0; i < sexpr.size(); i++)
{
- pstring x = pop_check(opstk, expr);
- while (x != "(")
+ pstring &s = sexpr[i];
+ if (s=="(")
+ opstk.push(s);
+ else if (s==")")
{
- postfix.push_back(x);
- x = pop_check(opstk, expr);
+ pstring x = pop_check(opstk, expr);
+ while (x != "(")
+ {
+ postfix.push_back(x);
+ x = pop_check(opstk, expr);
+ }
+ if (opstk.size() > 0 && get_prio(opstk.top()) == 0)
+ postfix.push_back(pop_check(opstk, expr));
}
- opstk.push(x);
- }
- else {
- int p = get_prio(s);
- if (p>0)
+ else if (s==",")
{
- if (opstk.size() == 0)
- opstk.push(s);
- else
+ pstring x = pop_check(opstk, expr);
+ while (x != "(")
{
- if (get_prio(opstk.top()) >= get_prio(s))
- postfix.push_back(pop_check(opstk, expr));
- opstk.push(s);
+ postfix.push_back(x);
+ x = pop_check(opstk, expr);
}
+ opstk.push(x);
}
- else if (p == 0) // Function or variable
- {
- if (sexpr[i+1] == "(")
- opstk.push(s);
+ else {
+ int p = get_prio(s);
+ if (p>0)
+ {
+ if (opstk.size() == 0)
+ opstk.push(s);
+ else
+ {
+ if (get_prio(opstk.top()) >= get_prio(s))
+ postfix.push_back(pop_check(opstk, expr));
+ opstk.push(s);
+ }
+ }
+ else if (p == 0) // Function or variable
+ {
+ if (sexpr[i+1] == "(")
+ opstk.push(s);
+ else
+ postfix.push_back(s);
+ }
else
postfix.push_back(s);
}
- else
- postfix.push_back(s);
}
+ while (opstk.size() > 0)
+ {
+ postfix.push_back(opstk.top());
+ opstk.pop();
+ }
+ compile_postfix(inputs, postfix, expr);
}
- while (opstk.size() > 0)
- {
- postfix.push_back(opstk.top());
- opstk.pop();
- }
- compile_postfix(inputs, postfix, expr);
-}
-#define ST1 stack[ptr]
-#define ST2 stack[ptr-1]
+ #define ST1 stack[ptr]
+ #define ST2 stack[ptr-1]
-#define OP(OP, ADJ, EXPR) \
-case OP: \
- ptr-= (ADJ); \
- stack[ptr-1] = (EXPR); \
- break;
+ #define OP(OP, ADJ, EXPR) \
+ case OP: \
+ ptr-= (ADJ); \
+ stack[ptr-1] = (EXPR); \
+ break;
-double pfunction::evaluate(const std::vector<double> &values) noexcept
-{
- std::array<double, 20> stack = { 0 };
- unsigned ptr = 0;
- stack[0] = 0.0;
- for (auto &rc : m_precompiled)
+ template <typename NT>
+ NT pfunction<NT>::evaluate(const std::vector<NT> &values) noexcept
{
- switch (rc.m_cmd)
+ std::array<NT, 20> stack = { 0 };
+ unsigned ptr = 0;
+ stack[0] = 0.0;
+ for (auto &rc : m_precompiled)
{
- OP(ADD, 1, ST2 + ST1)
- OP(MULT, 1, ST2 * ST1)
- OP(SUB, 1, ST2 - ST1)
- OP(DIV, 1, ST2 / ST1)
- OP(POW, 1, std::pow(ST2, ST1))
- OP(SIN, 0, std::sin(ST2))
- OP(COS, 0, std::cos(ST2))
- OP(TRUNC, 0, std::trunc(ST2))
- case RAND:
- stack[ptr++] = lfsr_random();
- break;
- case PUSH_INPUT:
- stack[ptr++] = values[static_cast<unsigned>(rc.m_param)];
- break;
- case PUSH_CONST:
- stack[ptr++] = rc.m_param;
- break;
+ switch (rc.m_cmd)
+ {
+ OP(ADD, 1, ST2 + ST1)
+ OP(MULT, 1, ST2 * ST1)
+ OP(SUB, 1, ST2 - ST1)
+ OP(DIV, 1, ST2 / ST1)
+ OP(POW, 1, std::pow(ST2, ST1))
+ OP(SIN, 0, std::sin(ST2))
+ OP(COS, 0, std::cos(ST2))
+ OP(TRUNC, 0, std::trunc(ST2))
+ case RAND:
+ stack[ptr++] = lfsr_random();
+ break;
+ case PUSH_INPUT:
+ stack[ptr++] = values[static_cast<unsigned>(rc.m_param)];
+ break;
+ case PUSH_CONST:
+ stack[ptr++] = rc.m_param;
+ break;
+ }
}
+ return stack[ptr-1];
}
- return stack[ptr-1];
-}
+
+ template struct pfunction<float>;
+ template struct pfunction<double>;
} // namespace plib