Like other plugins, solvers are loaded using the load command or -a cmdline argument. The SIM_DATA class has two matrices, _aa and _lu. The former for dc/tran/op (real valued) and the latter for small signal analysis like ac, pz, noise etc. (complex). SIM_DATA is currently statically instanciated in CKT_BASE::_sim.
A matrix is a BSMATRIX<numerical_type>, a “bump and spike” structure for storage. It has a pointer to a solver of type BSMATRIX_SOLVER<numerical_type>, which has a reference to the matrix to solve and a virtual interface. A solver plugin essentially attaches a solver to a matrix, replacing the current solver.
struct set{ set(){ auto x = new MY_SOLVER<double>(CKT_BASE::_sim->_aa); CKT_BASE::_sim->_aa.set_solver(x); } ~set(){ CKT_BASE::_sim->_aa.set_solver(nullptr); } } s;
The simulator will call virtual functions in the solver that MY_SOLVER is expected to implement. These are (see m_matrix.h for the definite interface) as follows.
virtual void init(int ss) = 0; virtual void uninit() = 0; virtual void iwant(int, int); virtual void allocate() = 0; virtual void unallocate() = 0; virtual void set_min_pivot(double x) = 0; virtual void lu_decomp(bool do_partial) = 0; virtual void fbsub(T*) const; virtual void fbsub(T* x, const T* b, T* c = nullptr)const; virtual void fbsubt(T*) const; virtual void zero(); virtual void load_diagonal_point(int i, T value); virtual void load_point(int i, int j, T value); virtual void load_couple(int i, int j, T value); virtual void load_symmetric(int i, int j, T value); virtual void load_asymmetric(int r1, int r2, int c1, int c2, T value);
Once a matrix is initialised (ss=number of rows/columns), it accepts “iwant” calls passing the coordinates that devices will load into later on. The allocate function is meant to arrange memory for both the load_* and lu_decomp calls. Forward/backward substitution is provided as usual, with variants for “separate output memory” and “transposed”.
Gnucap has two solvers built in and set by default, see m_matrix_solver.h. An in-place solver, LU_INPLACE, for use in small signal analysis. Another, LU_COPY, solves a copy of the matrix, allowing for partial updates, in cases where repeated solutions of very similar matrices are required.
A compressed sparse version of LU_COPY is (currently) available in tests/cbs.cc. It reduces both the memory use, by computing the exact footprint prior to allocation, and saves time by avoiding operations involving the known zeroes. It also tweaks propagation rules a bit, still numerical results are identical to LU_COPY, by construction.
Using alternative general purpose solvers like KLU or UMFPACK is relatively easy, and wrapper plugins are circulating. Now here's the platform to develop and benchmark the next generation (free/libre) matrix solvers ready for VLSI.