diff options
Diffstat (limited to 'src/lib/netlist/solver/nld_matrix_solver.cpp')
-rw-r--r-- | src/lib/netlist/solver/nld_matrix_solver.cpp | 226 |
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()) |