summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/netlist/solver/nld_matrix_solver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/netlist/solver/nld_matrix_solver.cpp')
-rw-r--r--src/lib/netlist/solver/nld_matrix_solver.cpp226
1 files changed, 170 insertions, 56 deletions
diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp
index d43d37eaf18..2c530b219cc 100644
--- a/src/lib/netlist/solver/nld_matrix_solver.cpp
+++ b/src/lib/netlist/solver/nld_matrix_solver.cpp
@@ -40,7 +40,7 @@ void terms_for_net_t::clear()
void terms_for_net_t::add(terminal_t *term, int net_other, bool sorted)
{
if (sorted)
- for (unsigned i=0; i < m_connected_net_idx.size(); i++)
+ for (std::size_t i=0; i < m_connected_net_idx.size(); i++)
{
if (m_connected_net_idx[i] > net_other)
{
@@ -63,7 +63,7 @@ void terms_for_net_t::add(terminal_t *term, int net_other, bool sorted)
void terms_for_net_t::set_pointers()
{
- for (unsigned i = 0; i < count(); i++)
+ for (std::size_t i = 0; i < count(); i++)
{
m_terms[i]->set_ptrs(&m_gt[i], &m_go[i], &m_Idr[i]);
m_connected_net_V[i] = m_terms[i]->m_otherterm->net().Q_Analog_state_ptr();
@@ -141,7 +141,7 @@ void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
{
proxied_analog_output_t *net_proxy_output = nullptr;
for (auto & input : m_inps)
- if (input->m_proxied_net == &p->net())
+ if (input->proxied_net() == &p->net())
{
net_proxy_output = input.get();
break;
@@ -150,11 +150,10 @@ void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
if (net_proxy_output == nullptr)
{
pstring nname = this->name() + "." + pstring(plib::pfmt("m{1}")(m_inps.size()));
- auto net_proxy_output_u = plib::make_unique<proxied_analog_output_t>(*this, nname);
+ nl_assert(p->net().is_analog());
+ auto net_proxy_output_u = plib::make_unique<proxied_analog_output_t>(*this, nname, static_cast<analog_net_t *>(&p->net()));
net_proxy_output = net_proxy_output_u.get();
m_inps.push_back(std::move(net_proxy_output_u));
- nl_assert(p->net().is_analog());
- net_proxy_output->m_proxied_net = static_cast<analog_net_t *>(&p->net());
}
net_proxy_output->net().add_terminal(*p);
// FIXME: repeated calling - kind of brute force
@@ -175,27 +174,8 @@ void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
setup_matrix();
}
-void matrix_solver_t::setup_matrix()
+void matrix_solver_t::sort_terms(eSortType sort)
{
- const std::size_t iN = m_nets.size();
-
- for (std::size_t k = 0; k < iN; k++)
- {
- m_terms[k]->m_railstart = m_terms[k]->count();
- for (std::size_t i = 0; i < m_rails_temp[k]->count(); i++)
- this->m_terms[k]->add(m_rails_temp[k]->terms()[i], m_rails_temp[k]->connected_net_idx()[i], false);
-
- m_terms[k]->set_pointers();
- }
-
- for (terms_for_net_t *rt : m_rails_temp)
- {
- rt->clear(); // no longer needed
- plib::pfree(rt); // no longer needed
- }
-
- m_rails_temp.clear();
-
/* Sort in descending order by number of connected matrix voltages.
* The idea is, that for Gauss-Seidel algo the first voltage computed
* depends on the greatest number of previous voltages thus taking into
@@ -216,28 +196,98 @@ void matrix_solver_t::setup_matrix()
*
*/
- if (m_sort != NOSORT)
- {
- int sort_order = (m_sort == DESCENDING ? 1 : -1);
+ const std::size_t iN = m_nets.size();
- for (unsigned k = 0; k < iN - 1; k++)
- for (unsigned i = k+1; i < iN; i++)
+ switch (sort)
+ {
+ case PREFER_BAND_MATRIX:
{
- if ((static_cast<int>(m_terms[k]->m_railstart) - static_cast<int>(m_terms[i]->m_railstart)) * sort_order < 0)
+ for (std::size_t k = 0; k < iN - 1; k++)
{
- std::swap(m_terms[i], m_terms[k]);
- std::swap(m_nets[i], m_nets[k]);
+ auto pk = get_weight_around_diag(k,k);
+ for (std::size_t i = k+1; i < iN; i++)
+ {
+ auto pi = get_weight_around_diag(i,k);
+ if (pi < pk)
+ {
+ std::swap(m_terms[i], m_terms[k]);
+ std::swap(m_nets[i], m_nets[k]);
+ pk = get_weight_around_diag(k,k);
+ }
+ }
}
}
+ break;
+ case PREFER_IDENTITY_TOP_LEFT:
+ {
+ for (std::size_t k = 0; k < iN - 1; k++)
+ {
+ auto pk = get_left_right_of_diag(k,k);
+ for (std::size_t i = k+1; i < iN; i++)
+ {
+ auto pi = get_left_right_of_diag(i,k);
+ if (pi.first <= pk.first && pi.second >= pk.second)
+ {
+ std::swap(m_terms[i], m_terms[k]);
+ std::swap(m_nets[i], m_nets[k]);
+ pk = get_left_right_of_diag(k,k);
+ }
+ }
+ }
+ }
+ break;
+ case ASCENDING:
+ case DESCENDING:
+ {
+ int sort_order = (m_sort == DESCENDING ? 1 : -1);
- for (auto &term : m_terms)
- {
- int *other = term->connected_net_idx();
- for (unsigned i = 0; i < term->count(); i++)
- if (other[i] != -1)
- other[i] = get_net_idx(&term->terms()[i]->m_otherterm->net());
- }
+ for (std::size_t k = 0; k < iN - 1; k++)
+ for (std::size_t i = k+1; i < iN; i++)
+ {
+ if ((static_cast<int>(m_terms[k]->m_railstart) - static_cast<int>(m_terms[i]->m_railstart)) * sort_order < 0)
+ {
+ std::swap(m_terms[i], m_terms[k]);
+ std::swap(m_nets[i], m_nets[k]);
+ }
+ }
+ }
+ break;
+ case NOSORT:
+ break;
+ }
+ /* rebuild */
+ for (auto &term : m_terms)
+ {
+ int *other = term->connected_net_idx();
+ for (std::size_t i = 0; i < term->count(); i++)
+ //FIXME: this is weird
+ if (other[i] != -1)
+ other[i] = get_net_idx(&term->terms()[i]->m_otherterm->net());
}
+}
+
+void matrix_solver_t::setup_matrix()
+{
+ const std::size_t iN = m_nets.size();
+
+ for (std::size_t k = 0; k < iN; k++)
+ {
+ m_terms[k]->m_railstart = m_terms[k]->count();
+ for (std::size_t i = 0; i < m_rails_temp[k]->count(); i++)
+ this->m_terms[k]->add(m_rails_temp[k]->terms()[i], m_rails_temp[k]->connected_net_idx()[i], false);
+
+ m_terms[k]->set_pointers();
+ }
+
+ for (terms_for_net_t *rt : m_rails_temp)
+ {
+ rt->clear(); // no longer needed
+ plib::pfree(rt); // no longer needed
+ }
+
+ m_rails_temp.clear();
+
+ sort_terms(m_sort);
/* create a list of non zero elements. */
for (unsigned k = 0; k < iN; k++)
@@ -248,7 +298,7 @@ void matrix_solver_t::setup_matrix()
t->m_nz.clear();
- for (unsigned i = 0; i < t->m_railstart; i++)
+ for (std::size_t i = 0; i < t->m_railstart; i++)
if (!plib::container::contains(t->m_nz, static_cast<unsigned>(other[i])))
t->m_nz.push_back(static_cast<unsigned>(other[i]));
@@ -262,7 +312,7 @@ void matrix_solver_t::setup_matrix()
* These list anticipate the population of array elements by
* Gaussian elimination.
*/
- for (unsigned k = 0; k < iN; k++)
+ for (std::size_t k = 0; k < iN; k++)
{
terms_for_net_t * t = m_terms[k].get();
/* pretty brutal */
@@ -282,7 +332,7 @@ void matrix_solver_t::setup_matrix()
}
}
- for (unsigned i = 0; i < t->m_railstart; i++)
+ for (std::size_t i = 0; i < t->m_railstart; i++)
if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(other[i])) && other[i] >= static_cast<int>(k + 1))
t->m_nzrd.push_back(static_cast<unsigned>(other[i]));
@@ -295,14 +345,14 @@ void matrix_solver_t::setup_matrix()
*/
bool **touched = plib::palloc_array<bool *>(iN);
- for (unsigned k=0; k<iN; k++)
+ for (std::size_t k=0; k<iN; k++)
touched[k] = plib::palloc_array<bool>(iN);
- for (unsigned k = 0; k < iN; k++)
+ for (std::size_t k = 0; k < iN; k++)
{
- for (unsigned j = 0; j < iN; j++)
+ for (std::size_t j = 0; j < iN; j++)
touched[k][j] = false;
- for (unsigned j = 0; j < m_terms[k]->m_nz.size(); j++)
+ for (std::size_t j = 0; j < m_terms[k]->m_nz.size(); j++)
touched[k][m_terms[k]->m_nz[j]] = true;
}
@@ -317,7 +367,7 @@ void matrix_solver_t::setup_matrix()
m_ops++;
if (!plib::container::contains(m_terms[k]->m_nzbd, row))
m_terms[k]->m_nzbd.push_back(row);
- for (unsigned col = k + 1; col < iN; col++)
+ for (std::size_t col = k + 1; col < iN; col++)
if (touched[k][col])
{
touched[row][col] = true;
@@ -329,10 +379,10 @@ void matrix_solver_t::setup_matrix()
log().verbose("Number of mults/adds for {1}: {2}", name(), m_ops);
if ((0))
- for (unsigned k = 0; k < iN; k++)
+ for (std::size_t k = 0; k < iN; k++)
{
pstring line = plib::pfmt("{1:3}")(k);
- for (unsigned j = 0; j < m_terms[k]->m_nzrd.size(); j++)
+ for (std::size_t j = 0; j < m_terms[k]->m_nzrd.size(); j++)
line += plib::pfmt(" {1:3}")(m_terms[k]->m_nzrd[j]);
log().verbose("{1}", line);
}
@@ -340,7 +390,7 @@ void matrix_solver_t::setup_matrix()
/*
* save states
*/
- for (unsigned k = 0; k < iN; k++)
+ for (std::size_t k = 0; k < iN; k++)
{
pstring num = plib::pfmt("{1}")(k);
@@ -353,7 +403,7 @@ void matrix_solver_t::setup_matrix()
state().save(*this, m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count());
}
- for (unsigned k=0; k<iN; k++)
+ for (std::size_t k=0; k<iN; k++)
plib::pfree_array(touched[k]);
plib::pfree_array(touched);
}
@@ -362,7 +412,7 @@ void matrix_solver_t::update_inputs()
{
// avoid recursive calls. Inputs are updated outside this call
for (auto &inp : m_inps)
- inp->push(inp->m_proxied_net->Q_Analog());
+ inp->push(inp->proxied_net()->Q_Analog());
}
void matrix_solver_t::update_dynamic()
@@ -413,8 +463,8 @@ void matrix_solver_t::solve_base()
++m_stat_vsolver_calls;
if (has_dynamic_devices())
{
- unsigned this_resched;
- unsigned newton_loops = 0;
+ std::size_t this_resched;
+ std::size_t newton_loops = 0;
do
{
update_dynamic();
@@ -464,6 +514,70 @@ int matrix_solver_t::get_net_idx(detail::net_t *net)
return -1;
}
+std::pair<int, int> matrix_solver_t::get_left_right_of_diag(std::size_t irow, std::size_t idiag)
+{
+ /*
+ * return the maximum column left of the diagonal (-1 if no cols found)
+ * return the minimum column right of the diagonal (999999 if no cols found)
+ */
+
+ const int row = static_cast<int>(irow);
+ const int diag = static_cast<int>(idiag);
+
+ int colmax = -1;
+ int colmin = 999999;
+
+ auto &term = m_terms[irow];
+
+ for (std::size_t i = 0; i < term->count(); i++)
+ {
+ auto col = get_net_idx(&term->terms()[i]->m_otherterm->net());
+ if (col != -1)
+ {
+ if (col==row) col = diag;
+ else if (col==diag) col = row;
+
+ if (col > diag && col < colmin)
+ colmin = col;
+ else if (col < diag && col > colmax)
+ colmax = col;
+ }
+ }
+ return std::pair<int, int>(colmax, colmin);
+}
+
+double matrix_solver_t::get_weight_around_diag(std::size_t row, std::size_t diag)
+{
+ {
+ /*
+ * return average absolute distance
+ */
+
+ std::vector<bool> touched(1024, false); // FIXME!
+
+ double weight = 0.0;
+ auto &term = m_terms[row];
+ for (std::size_t i = 0; i < term->count(); i++)
+ {
+ auto col = get_net_idx(&term->terms()[i]->m_otherterm->net());
+ if (col >= 0)
+ {
+ std::size_t colu = static_cast<std::size_t>(col);
+ if (!touched[colu])
+ {
+ if (colu==row) colu = static_cast<unsigned>(diag);
+ else if (colu==diag) colu = static_cast<unsigned>(row);
+
+ weight = weight + std::abs(static_cast<double>(colu) - static_cast<double>(diag));
+ touched[colu] = true;
+ }
+ }
+ }
+ return weight; // / static_cast<double>(term->m_railstart);
+ }
+}
+
+
void matrix_solver_t::add_term(std::size_t k, terminal_t *term)
{
if (term->m_otherterm->net().isRailNet())