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.
This commit is contained in:
couriersud 2019-10-31 21:53:50 +01:00
parent 6c075e602c
commit c6b281685d
14 changed files with 298 additions and 238 deletions

View File

@ -1266,13 +1266,12 @@ void netlist_mame_cpu_device::device_start()
{
if (n->is_logic())
{
state_add(index, n->name().c_str(), *(downcast<netlist::logic_net_t &>(*n).Q_state_ptr()));
state_add(index++, n->name().c_str(), *(downcast<netlist::logic_net_t &>(*n).Q_state_ptr()));
}
else
{
state_add(index, n->name().c_str(), *(downcast<netlist::analog_net_t &>(*n).Q_Analog_state_ptr()));
//state_add(index++, n->name().c_str(), *(downcast<netlist::analog_net_t &>(*n).Q_Analog_state_ptr()));
}
index++;
}
// set our instruction counter

View File

@ -319,7 +319,7 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
netlist::param_num_t<double> *m_param;
netlist::param_num_t<nl_fptype> *m_param;
bool m_auto_port;
const char *m_param_name;
double m_value_for_device_timer;

View File

@ -158,12 +158,12 @@ namespace analog
//printf("%s: %g %g\n", m_name.c_str(), nVd, (nl_fptype) m_Vd);
if (nVd > m_Vcrit)
{
const nl_fptype d = std::min(1e100, nVd - m_Vd);
const nl_fptype d = std::min(fp_constants<nl_fptype>::DIODE_MAXDIFF, nVd - m_Vd);
const nl_fptype a = std::abs(d) * m_VtInv;
m_Vd = m_Vd + (d < 0 ? -1.0 : 1.0) * std::log1p(a) * m_Vt;
}
else
m_Vd = std::max(-1e100, nVd);
m_Vd = std::max(-fp_constants<nl_fptype>::DIODE_MAXDIFF, nVd);
//m_Vd = nVd;
if (m_Vd < m_Vmin)
@ -189,7 +189,7 @@ namespace analog
else /* log stepping should already be done in mosfet */
{
m_Vd = nVd;
IseVDVt = std::exp(std::min(300.0, m_logIs + m_Vd * m_VtInv));
IseVDVt = std::exp(std::min(fp_constants<nl_fptype>::DIODE_MAXVOLT, m_logIs + m_Vd * m_VtInv));
m_Id = IseVDVt - m_Is;
m_G = IseVDVt * m_VtInv + m_gmin;
}

View File

@ -430,7 +430,7 @@ namespace analog
param_fp_t m_R;
param_fp_t m_V;
param_str_t m_func;
plib::pfunction m_compiled;
plib::pfunction<nl_fptype> m_compiled;
std::vector<nl_fptype> m_funcparam;
};
@ -486,7 +486,7 @@ namespace analog
state_var<nl_fptype> m_t;
param_fp_t m_I;
param_str_t m_func;
plib::pfunction m_compiled;
plib::pfunction<nl_fptype> m_compiled;
std::vector<nl_fptype> m_funcparam;
};

View File

@ -149,7 +149,7 @@ namespace devices
logic_output_t m_Q;
param_str_t m_func;
plib::pfunction m_compiled;
plib::pfunction<nl_fptype> m_compiled;
std::vector<nl_fptype> m_funcparam;
};
@ -389,7 +389,7 @@ namespace devices
std::vector<unique_pool_ptr<analog_input_t>> m_I;
std::vector<nl_fptype> m_vals;
plib::pfunction m_compiled;
plib::pfunction<nl_fptype> m_compiled;
};
// -----------------------------------------------------------------------------

View File

@ -96,7 +96,52 @@
static constexpr const auto NETLIST_INTERNAL_RES = 1000000000;
static constexpr const auto NETLIST_CLOCK = NETLIST_INTERNAL_RES;
//#define nl_fptype float
//============================================================
// Floating point types used
//
// Don't change this. Simple analog circuits like pong
// work with float. Kidniki just doesn't work at all
// due to numeric issues
//============================================================
using nl_fptype = double;
//using nl_fptype = float;
using nl_mat_fptype = nl_fptype;
namespace netlist
{
/*! Specific constants depending on floating type
*
* @tparam FT floating point type: double/float
*/
template <typename FT>
struct fp_constants
{ };
/*! Specific constants for double floating point type
*/
template <>
struct fp_constants<double>
{
static constexpr const double DIODE_MAXDIFF = 1e100;
static constexpr const double DIODE_MAXVOLT = 300.0;
static constexpr const double TIMESTEP_MAXDIFF = 1e100;
static constexpr const double TIMESTEP_MINDIV = 1e-60;
};
/*! Specific constants for float floating point type
*/
template <>
struct fp_constants<float>
{
static constexpr const float DIODE_MAXDIFF = 1e5;
static constexpr const float DIODE_MAXVOLT = 30.0;
static constexpr const float TIMESTEP_MAXDIFF = 1e30;
static constexpr const float TIMESTEP_MINDIV = 1e-8;
};
} // namespace netlist
#endif /* NLCONFIG_H_ */

View File

@ -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
{
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_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);
compile_infix(inputs, 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++)
template <typename NT>
void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr)
{
pstring &s = sexpr[i];
if (s=="(")
opstk.push(s);
else if (s==")")
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)
{
pstring x = pop_check(opstk, expr);
while (x != "(")
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
{
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==",")
{
pstring x = pop_check(opstk, expr);
while (x != "(")
{
postfix.push_back(x);
x = pop_check(opstk, expr);
}
opstk.push(x);
}
else {
int p = get_prio(s);
if (p>0)
{
if (opstk.size() == 0)
opstk.push(s);
else
for (std::size_t i = 0; i < inputs.size(); i++)
{
if (get_prio(opstk.top()) >= get_prio(s))
postfix.push_back(pop_check(opstk, expr));
opstk.push(s);
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_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;
}
}
else if (p == 0) // Function or variable
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));
}
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;
}
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 &s = sexpr[i];
if (s=="(")
opstk.push(s);
else if (s==")")
{
if (sexpr[i+1] == "(")
opstk.push(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==",")
{
pstring x = pop_check(opstk, expr);
while (x != "(")
{
postfix.push_back(x);
x = pop_check(opstk, expr);
}
opstk.push(x);
}
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);
}
#define ST1 stack[ptr]
#define ST2 stack[ptr-1]
#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)
{
switch (rc.m_cmd)
while (opstk.size() > 0)
{
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;
postfix.push_back(opstk.top());
opstk.pop();
}
compile_postfix(inputs, postfix, expr);
}
return 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;
template <typename NT>
NT pfunction<NT>::evaluate(const std::vector<NT> &values) noexcept
{
std::array<NT, 20> stack = { 0 };
unsigned ptr = 0;
stack[0] = 0.0;
for (auto &rc : m_precompiled)
{
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];
}
template struct pfunction<float>;
template struct pfunction<double>;
} // namespace plib

View File

@ -21,7 +21,9 @@ namespace plib {
/*! Class providing support for evaluating expressions
*
* @tparam NT Number type, should be float or double
*/
template <typename NT>
class pfunction
{
enum rpn_cmd
@ -42,7 +44,7 @@ namespace plib {
{
rpn_inst() : m_cmd(ADD), m_param(0.0) { }
rpn_cmd m_cmd;
double m_param;
NT m_param;
};
public:
/*! Constructor with state saving support
@ -91,20 +93,20 @@ namespace plib {
* @param values for input variables, e.g. {1.1, 2.2}
* @return value of expression
*/
double evaluate(const std::vector<double> &values) noexcept;
NT evaluate(const std::vector<NT> &values) noexcept;
private:
void compile_postfix(const std::vector<pstring> &inputs,
const std::vector<pstring> &cmds, const pstring &expr);
double lfsr_random() noexcept
NT lfsr_random() noexcept
{
std::uint16_t lsb = m_lfsr & 1;
m_lfsr >>= 1;
if (lsb)
m_lfsr ^= 0xB400u; // taps 15, 13, 12, 10
return static_cast<double>(m_lfsr) / static_cast<double>(0xffffu);
return static_cast<NT>(m_lfsr) / static_cast<NT>(0xffffu);
}
std::vector<rpn_inst> m_precompiled; //!< precompiled expression
@ -112,6 +114,8 @@ namespace plib {
std::uint16_t m_lfsr; //!< lfsr used for generating random numbers
};
extern template struct pfunction<float>;
extern template struct pfunction<double>;
} // namespace plib

View File

@ -311,11 +311,14 @@ struct input_t
: m_value(0.0)
{
std::array<char, 400> buf; // NOLINT(cppcoreguidelines-pro-type-member-init)
nl_fptype t(0);
double t(0);
double val(0);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
int e = std::sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf.data(), &m_value);
int e = std::sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf.data(), &val);
if (e != 3)
throw netlist::nl_exception(plib::pfmt("error {1} scanning line {2}\n")(e)(line));
m_value = static_cast<nl_fptype>(val);
m_time = netlist::netlist_time::from_double(t);
m_param = setup.find_param(pstring(buf.data()), true);
}

View File

@ -565,7 +565,7 @@ namespace solver
//const nl_fptype DD_n = (n->Q_Analog() - t->m_last_V);
// avoid floating point exceptions
const nl_fptype DD_n = std::max(-1e100, std::min(1e100,(t.getV() - m_last_V[k])));
const nl_fptype DD_n = std::max(-fp_constants<nl_fptype>::TIMESTEP_MAXDIFF, std::min(fp_constants<nl_fptype>::TIMESTEP_MAXDIFF,(t.getV() - m_last_V[k])));
const nl_fptype hn = cur_ts;
//printf("%g %g %g %g\n", DD_n, hn, t.m_DD_n_m_1, t.m_h_n_m_1);
@ -574,7 +574,7 @@ namespace solver
m_h_n_m_1[k] = hn;
m_DD_n_m_1[k] = DD_n;
if (std::fabs(DD2) > plib::constants<nl_fptype>::cast(1e-60)) // avoid div-by-zero
if (std::fabs(DD2) > fp_constants<nl_fptype>::TIMESTEP_MINDIV) // avoid div-by-zero
new_net_timestep = std::sqrt(m_params.m_dynamic_lte / std::fabs(plib::constants<nl_fptype>::cast(0.5)*DD2));
else
new_net_timestep = m_params.m_max_timestep;

View File

@ -383,7 +383,7 @@ namespace solver
plib::pmatrix2d<nl_fptype, aligned_alloc<nl_fptype>> m_gonn;
plib::pmatrix2d<nl_fptype, aligned_alloc<nl_fptype>> m_gtn;
plib::pmatrix2d<nl_fptype, aligned_alloc<nl_fptype>> m_Idrn;
plib::pmatrix2d<nl_fptype *, aligned_alloc<nl_fptype *>> m_mat_ptr;
plib::pmatrix2d<nl_mat_fptype *, aligned_alloc<nl_mat_fptype *>> m_mat_ptr;
plib::pmatrix2d<nl_fptype *, aligned_alloc<nl_fptype *>> m_connected_net_Vn;
plib::aligned_vector<terms_for_net_t> m_terms;
@ -439,9 +439,10 @@ namespace solver
*/
const std::size_t iN = this->m_terms.size();
typename std::decay<decltype(V[0])>::type cerr = 0;
using vtype = typename std::decay<decltype(V[0])>::type;
vtype cerr = 0;
for (std::size_t i = 0; i < iN; i++)
cerr = std::max(cerr, std::abs(V[i] - this->m_terms[i].getV()));
cerr = std::max(cerr, std::abs(V[i] - static_cast<vtype>(this->m_terms[i].getV())));
return cerr;
}

View File

@ -131,7 +131,7 @@ namespace solver
mat_type mat;
plib::dynproc<void, nl_fptype * , nl_fptype * , nl_fptype * > m_proc;
plib::dynproc<void, FT * , FT * , FT * > m_proc;
};

View File

@ -79,9 +79,9 @@ namespace solver
float_type RHS_t = 0.0;
const std::size_t term_count = this->m_terms[k].count();
const float_type * const gt = this->m_gtn[k];
const float_type * const go = this->m_gonn[k];
const float_type * const Idr = this->m_Idrn[k];
const nl_fptype * const gt = this->m_gtn[k];
const nl_fptype * const go = this->m_gonn[k];
const nl_fptype * const Idr = this->m_Idrn[k];
auto other_cur_analog = this->m_connected_net_Vn[k];
this->m_new_V[k] = this->m_terms[k].getV();
@ -130,7 +130,7 @@ namespace solver
{
const int * net_other = this->m_terms[k].m_connected_net_idx.data();
const std::size_t railstart = this->m_terms[k].railstart();
const float_type * go = this->m_gonn[k];
const nl_fptype * go = this->m_gonn[k];
float_type Idrive = 0.0;
for (std::size_t i = 0; i < railstart; i++)

View File

@ -231,62 +231,62 @@ namespace devices
switch (net_count)
{
case 1:
ms = plib::make_unique<solver::matrix_solver_direct1_t<nl_fptype>>(state(), sname, grp, &m_params);
ms = plib::make_unique<solver::matrix_solver_direct1_t<nl_mat_fptype>>(state(), sname, grp, &m_params);
break;
case 2:
ms = plib::make_unique<solver::matrix_solver_direct2_t<nl_fptype>>(state(), sname, grp, &m_params);
ms = plib::make_unique<solver::matrix_solver_direct2_t<nl_mat_fptype>>(state(), sname, grp, &m_params);
break;
#if 0
case 3:
ms = create_solver<nl_fptype, 3>(3, sname, grp);
ms = create_solver<nl_mat_fptype, 3>(3, sname, grp);
break;
case 4:
ms = create_solver<nl_fptype, 4>(4, sname, grp);
ms = create_solver<nl_mat_fptype, 4>(4, sname, grp);
break;
case 5:
ms = create_solver<nl_fptype, 5>(5, sname, grp);
ms = create_solver<nl_mat_fptype, 5>(5, sname, grp);
break;
case 6:
ms = create_solver<nl_fptype, 6>(6, sname, grp);
ms = create_solver<nl_mat_fptype, 6>(6, sname, grp);
break;
case 7:
ms = create_solver<nl_fptype, 7>(7, sname, grp);
ms = create_solver<nl_mat_fptype, 7>(7, sname, grp);
break;
case 8:
ms = create_solver<nl_fptype, 8>(8, sname, grp);
ms = create_solver<nl_mat_fptype, 8>(8, sname, grp);
break;
case 9:
ms = create_solver<nl_fptype, 9>(9, sname, grp);
ms = create_solver<nl_mat_fptype, 9>(9, sname, grp);
break;
case 10:
ms = create_solver<nl_fptype, 10>(10, sname, grp);
ms = create_solver<nl_mat_fptype, 10>(10, sname, grp);
break;
#if 0
case 11:
ms = create_solver<nl_fptype, 11>(11, sname);
ms = create_solver<nl_mat_fptype, 11>(11, sname);
break;
case 12:
ms = create_solver<nl_fptype, 12>(12, sname);
ms = create_solver<nl_mat_fptype, 12>(12, sname);
break;
case 15:
ms = create_solver<nl_fptype, 15>(15, sname);
ms = create_solver<nl_mat_fptype, 15>(15, sname);
break;
case 31:
ms = create_solver<nl_fptype, 31>(31, sname);
ms = create_solver<nl_mat_fptype, 31>(31, sname);
break;
case 35:
ms = create_solver<nl_fptype, 35>(35, sname);
ms = create_solver<nl_mat_fptype, 35>(35, sname);
break;
case 43:
ms = create_solver<nl_fptype, 43>(43, sname);
ms = create_solver<nl_mat_fptype, 43>(43, sname);
break;
case 49:
ms = create_solver<nl_fptype, 49>(49, sname);
ms = create_solver<nl_mat_fptype, 49>(49, sname);
break;
#endif
#if 1
case 87:
ms = create_solver<nl_fptype,86>(86, sname, grp);
ms = create_solver<nl_mat_fptype,86>(86, sname, grp);
break;
#endif
#endif
@ -294,35 +294,35 @@ namespace devices
log().info(MI_NO_SPECIFIC_SOLVER(net_count));
if (net_count <= 8)
{
ms = create_solver<nl_fptype, -8>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, -8>(net_count, sname, grp);
}
else if (net_count <= 16)
{
ms = create_solver<nl_fptype, -16>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, -16>(net_count, sname, grp);
}
else if (net_count <= 32)
{
ms = create_solver<nl_fptype, -32>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, -32>(net_count, sname, grp);
}
else if (net_count <= 64)
{
ms = create_solver<nl_fptype, -64>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, -64>(net_count, sname, grp);
}
else if (net_count <= 128)
{
ms = create_solver<nl_fptype, -128>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, -128>(net_count, sname, grp);
}
else if (net_count <= 256)
{
ms = create_solver<nl_fptype, -256>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, -256>(net_count, sname, grp);
}
else if (net_count <= 512)
{
ms = create_solver<nl_fptype, -512>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, -512>(net_count, sname, grp);
}
else
{
ms = create_solver<nl_fptype, 0>(net_count, sname, grp);
ms = create_solver<nl_mat_fptype, 0>(net_count, sname, grp);
}
break;
}