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()) 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 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 // 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; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private: private:
netlist::param_num_t<double> *m_param; netlist::param_num_t<nl_fptype> *m_param;
bool m_auto_port; bool m_auto_port;
const char *m_param_name; const char *m_param_name;
double m_value_for_device_timer; 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); //printf("%s: %g %g\n", m_name.c_str(), nVd, (nl_fptype) m_Vd);
if (nVd > m_Vcrit) 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; const nl_fptype a = std::abs(d) * m_VtInv;
m_Vd = m_Vd + (d < 0 ? -1.0 : 1.0) * std::log1p(a) * m_Vt; m_Vd = m_Vd + (d < 0 ? -1.0 : 1.0) * std::log1p(a) * m_Vt;
} }
else else
m_Vd = std::max(-1e100, nVd); m_Vd = std::max(-fp_constants<nl_fptype>::DIODE_MAXDIFF, nVd);
//m_Vd = nVd; //m_Vd = nVd;
if (m_Vd < m_Vmin) if (m_Vd < m_Vmin)
@ -189,7 +189,7 @@ namespace analog
else /* log stepping should already be done in mosfet */ else /* log stepping should already be done in mosfet */
{ {
m_Vd = nVd; 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_Id = IseVDVt - m_Is;
m_G = IseVDVt * m_VtInv + m_gmin; m_G = IseVDVt * m_VtInv + m_gmin;
} }

View File

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

View File

@ -149,7 +149,7 @@ namespace devices
logic_output_t m_Q; logic_output_t m_Q;
param_str_t m_func; param_str_t m_func;
plib::pfunction m_compiled; plib::pfunction<nl_fptype> m_compiled;
std::vector<nl_fptype> m_funcparam; std::vector<nl_fptype> m_funcparam;
}; };
@ -389,7 +389,7 @@ namespace devices
std::vector<unique_pool_ptr<analog_input_t>> m_I; std::vector<unique_pool_ptr<analog_input_t>> m_I;
std::vector<nl_fptype> m_vals; 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_INTERNAL_RES = 1000000000;
static constexpr const auto NETLIST_CLOCK = NETLIST_INTERNAL_RES; 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 = 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_ */ #endif /* NLCONFIG_H_ */

View File

@ -16,23 +16,26 @@
namespace plib { namespace plib {
void pfunction::compile(const std::vector<pstring> &inputs, const pstring &expr) template <typename NT>
{ void pfunction<NT>::compile(const std::vector<pstring> &inputs, const pstring &expr)
{
if (plib::startsWith(expr, "rpn:")) if (plib::startsWith(expr, "rpn:"))
compile_postfix(inputs, expr.substr(4)); compile_postfix(inputs, expr.substr(4));
else else
compile_infix(inputs, expr); compile_infix(inputs, expr);
} }
void pfunction::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr) template <typename NT>
{ void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr)
{
std::vector<pstring> cmds(plib::psplit(expr, " ")); std::vector<pstring> cmds(plib::psplit(expr, " "));
compile_postfix(inputs, cmds, expr); compile_postfix(inputs, cmds, expr);
} }
void pfunction::compile_postfix(const std::vector<pstring> &inputs, template <typename NT>
void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs,
const std::vector<pstring> &cmds, const pstring &expr) const std::vector<pstring> &cmds, const pstring &expr)
{ {
m_precompiled.clear(); m_precompiled.clear();
int stk = 0; int stk = 0;
@ -85,10 +88,10 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs,
} }
if (stk != 1) if (stk != 1)
throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr)); throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr));
} }
static int get_prio(const pstring &v) static int get_prio(const pstring &v)
{ {
if (v == "(" || v == ")") if (v == "(" || v == ")")
return 1; return 1;
else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z")
@ -101,19 +104,20 @@ static int get_prio(const pstring &v)
return 30; return 30;
else else
return -1; return -1;
} }
static pstring pop_check(std::stack<pstring> &stk, const pstring &expr) static pstring pop_check(std::stack<pstring> &stk, const pstring &expr)
{ {
if (stk.size() == 0) if (stk.size() == 0)
throw plib::pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr)); throw plib::pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr));
pstring res = stk.top(); pstring res = stk.top();
stk.pop(); stk.pop();
return res; return res;
} }
void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring &expr) template <typename NT>
{ void pfunction<NT>::compile_infix(const std::vector<pstring> &inputs, const pstring &expr)
{
// Shunting-yard infix parsing // Shunting-yard infix parsing
std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"}; std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"};
std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep)); std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep));
@ -176,21 +180,22 @@ void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring
opstk.pop(); opstk.pop();
} }
compile_postfix(inputs, postfix, expr); compile_postfix(inputs, postfix, expr);
} }
#define ST1 stack[ptr] #define ST1 stack[ptr]
#define ST2 stack[ptr-1] #define ST2 stack[ptr-1]
#define OP(OP, ADJ, EXPR) \ #define OP(OP, ADJ, EXPR) \
case OP: \ case OP: \
ptr-= (ADJ); \ ptr-= (ADJ); \
stack[ptr-1] = (EXPR); \ stack[ptr-1] = (EXPR); \
break; break;
double pfunction::evaluate(const std::vector<double> &values) noexcept template <typename NT>
{ NT pfunction<NT>::evaluate(const std::vector<NT> &values) noexcept
std::array<double, 20> stack = { 0 }; {
std::array<NT, 20> stack = { 0 };
unsigned ptr = 0; unsigned ptr = 0;
stack[0] = 0.0; stack[0] = 0.0;
for (auto &rc : m_precompiled) for (auto &rc : m_precompiled)
@ -217,6 +222,9 @@ double pfunction::evaluate(const std::vector<double> &values) noexcept
} }
} }
return stack[ptr-1]; return stack[ptr-1];
} }
template struct pfunction<float>;
template struct pfunction<double>;
} // namespace plib } // namespace plib

View File

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

View File

@ -311,11 +311,14 @@ struct input_t
: m_value(0.0) : m_value(0.0)
{ {
std::array<char, 400> buf; // NOLINT(cppcoreguidelines-pro-type-member-init) 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) // 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) if (e != 3)
throw netlist::nl_exception(plib::pfmt("error {1} scanning line {2}\n")(e)(line)); 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_time = netlist::netlist_time::from_double(t);
m_param = setup.find_param(pstring(buf.data()), true); 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); //const nl_fptype DD_n = (n->Q_Analog() - t->m_last_V);
// avoid floating point exceptions // 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; 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); //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_h_n_m_1[k] = hn;
m_DD_n_m_1[k] = DD_n; 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)); new_net_timestep = std::sqrt(m_params.m_dynamic_lte / std::fabs(plib::constants<nl_fptype>::cast(0.5)*DD2));
else else
new_net_timestep = m_params.m_max_timestep; 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_gonn;
plib::pmatrix2d<nl_fptype, aligned_alloc<nl_fptype>> m_gtn; 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_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::pmatrix2d<nl_fptype *, aligned_alloc<nl_fptype *>> m_connected_net_Vn;
plib::aligned_vector<terms_for_net_t> m_terms; plib::aligned_vector<terms_for_net_t> m_terms;
@ -439,9 +439,10 @@ namespace solver
*/ */
const std::size_t iN = this->m_terms.size(); 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++) 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; return cerr;
} }

View File

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

View File

@ -231,62 +231,62 @@ namespace devices
switch (net_count) switch (net_count)
{ {
case 1: 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; break;
case 2: 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; break;
#if 0 #if 0
case 3: case 3:
ms = create_solver<nl_fptype, 3>(3, sname, grp); ms = create_solver<nl_mat_fptype, 3>(3, sname, grp);
break; break;
case 4: case 4:
ms = create_solver<nl_fptype, 4>(4, sname, grp); ms = create_solver<nl_mat_fptype, 4>(4, sname, grp);
break; break;
case 5: case 5:
ms = create_solver<nl_fptype, 5>(5, sname, grp); ms = create_solver<nl_mat_fptype, 5>(5, sname, grp);
break; break;
case 6: case 6:
ms = create_solver<nl_fptype, 6>(6, sname, grp); ms = create_solver<nl_mat_fptype, 6>(6, sname, grp);
break; break;
case 7: case 7:
ms = create_solver<nl_fptype, 7>(7, sname, grp); ms = create_solver<nl_mat_fptype, 7>(7, sname, grp);
break; break;
case 8: case 8:
ms = create_solver<nl_fptype, 8>(8, sname, grp); ms = create_solver<nl_mat_fptype, 8>(8, sname, grp);
break; break;
case 9: case 9:
ms = create_solver<nl_fptype, 9>(9, sname, grp); ms = create_solver<nl_mat_fptype, 9>(9, sname, grp);
break; break;
case 10: case 10:
ms = create_solver<nl_fptype, 10>(10, sname, grp); ms = create_solver<nl_mat_fptype, 10>(10, sname, grp);
break; break;
#if 0 #if 0
case 11: case 11:
ms = create_solver<nl_fptype, 11>(11, sname); ms = create_solver<nl_mat_fptype, 11>(11, sname);
break; break;
case 12: case 12:
ms = create_solver<nl_fptype, 12>(12, sname); ms = create_solver<nl_mat_fptype, 12>(12, sname);
break; break;
case 15: case 15:
ms = create_solver<nl_fptype, 15>(15, sname); ms = create_solver<nl_mat_fptype, 15>(15, sname);
break; break;
case 31: case 31:
ms = create_solver<nl_fptype, 31>(31, sname); ms = create_solver<nl_mat_fptype, 31>(31, sname);
break; break;
case 35: case 35:
ms = create_solver<nl_fptype, 35>(35, sname); ms = create_solver<nl_mat_fptype, 35>(35, sname);
break; break;
case 43: case 43:
ms = create_solver<nl_fptype, 43>(43, sname); ms = create_solver<nl_mat_fptype, 43>(43, sname);
break; break;
case 49: case 49:
ms = create_solver<nl_fptype, 49>(49, sname); ms = create_solver<nl_mat_fptype, 49>(49, sname);
break; break;
#endif #endif
#if 1 #if 1
case 87: case 87:
ms = create_solver<nl_fptype,86>(86, sname, grp); ms = create_solver<nl_mat_fptype,86>(86, sname, grp);
break; break;
#endif #endif
#endif #endif
@ -294,35 +294,35 @@ namespace devices
log().info(MI_NO_SPECIFIC_SOLVER(net_count)); log().info(MI_NO_SPECIFIC_SOLVER(net_count));
if (net_count <= 8) 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) 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) 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) 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) 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) 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) 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 else
{ {
ms = create_solver<nl_fptype, 0>(net_count, sname, grp); ms = create_solver<nl_mat_fptype, 0>(net_count, sname, grp);
} }
break; break;
} }