bump to -rc12
[gnucap-felix.git] / src / m_matrix.h
blobe7bdaf7f8fb0e3adec615351033f2daabf5cc68d
1 /* -*- C++ -*-
2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * Sparse matrix package
23 * Bump and spike - bordered block diagonal pattern
24 * -------------------------------------------------
25 * To use it (simple method) .....
26 * 1. Declare it ...
27 * BSMATRIX<double> a;
28 * 2. Then tell it what slots to allocate, in a loop ...
29 * for (all pairs i,j that might exist)
30 * a.iwant(i,j);
31 * 3. Then do the actual allocation ...
32 * a.allocate();
33 * 4. If you want, you can add an offset to the diagonal ...
34 * a.dezero(gmin);
35 * 5. You probably should set a minimum pivot value ...
36 * a.set_min_pivot(gmin);
37 * 6. Fill in the matrix ...
38 * for (all pairs i,j you want to fill in)
39 * a.m(i,j) += data;
40 * 7. Then do the LU decomposition ...
41 * a.lu_decomp();
42 * 8. Then get the solution by applying the right side vector (v)
43 * and doing the fwd and back substitution.
44 * a.fbsub(v);
45 * The solution is now in v.
46 * -------------------------------------------------
47 * To reuse it .....
48 * Get rid of the old data ...
49 * a.zero().
50 * Restore the offset, if you want ...
51 * a.dezero(gmin);
52 * Then fill and solve as before. (steps 6-8)
53 * -------------------------------------------------
54 * In the above case, LU replaced the matrix and the solution replaced
55 * the right side, losing the data.
56 * To keep the matrix, and keep the right side ...
57 * 1. Declare two matrices ...
58 * BSMATRIX<double> a;
59 * BSMATRIX<double> lu;
60 * 2. as before
61 * 2a. Say the lu has the same structure as a.
62 * lu.clone(a);
63 * 3-5. Allocate both.
64 * 6. Fill in "a" only.
65 * 7. Do the LU decomposition, keeping a, with result in lu ...
66 * lu.lu_decomp(a, false);
67 * 8. Do the f&B sub, keeping b (the right side), with result in x ...
68 * lu.fbsub(x, b);
69 * -------------------------------------------------
70 * To make a change to the matrix and re-solve ...
71 * Apply the change to a ...
72 * for (all changes you want to make)
73 * a.m(i,j) += delta; a.set_changed(i).set_changed(j)
74 * Then solve again .. step 7 above for a full solution,
75 * or for an update ...
76 * lu.lu_decomp(a, true);
77 * Then do the same step 8 as above.
78 * -------------------------------------------------
79 * some other functions that might be useful ....
80 * reinit(newsize) -- change the size (and lose the contents and structure)
81 * size()const -- return the size (# of rows & cols)
82 * density()const -- return the matrix density, as a number between 0 and 1
83 * sparsity()const -- 1-density
84 * -------------------------------------------------
85 * individual element access ...
86 * 5 access functions are provided.
87 * All return lvalues (references to the actual entry).
88 * All take 2 args, row and column. They differ in speed and generality.
89 * Since they are used in equations, they all have 1 letter names.
90 * s(r,c) -- "safe" -- most general case, with bounds checking
91 * if completely out of bounds, returns trash
92 * if in the matrix but out of band, returns a reference to zero
93 * Changing it will corrupt the matrix.
94 * All others have no bounds checking.
95 * m(r,c) -- "matrix" -- known to be within the allocated band
96 * r,c) -- "upper" -- known to be in the upper triangle. (c>=r)
97 * l(r,c) -- "lower" -- known to be in the lower triangle. (r>=c)
98 * d(r,c) -- "diagonal" -- known to be on the diagonal. (r==c)
99 * Using s() will always work, but will be slower than the other methods.
100 * You should use the most restricted function that you know is correct.
101 * -------------------------------------------------
102 * Other notes ...
103 * The numbering starts at 1 (Fortran style).
104 * When using "s" access, it is ok to load row and column 0, then ignore it.
105 * This may simplify load functions, at the expense of run speed.
106 * "s" will let you change the value of zero,
107 * but you will find out about it later.
109 //testing=script 2016.09.14
110 #ifndef M_MATRIX_H
111 #define M_MATRIX_H
112 /*--------------------------------------------------------------------------*/
113 #include "l_stlextra.h"
114 #include "io_.h"
115 #include <iostream>
116 #include <fstream>
117 #include <set>
118 /*--------------------------------------------------------------------------*/
119 enum needed_t {nNO=0, nYES, nFILL};
120 /*--------------------------------------------------------------------------*/
121 class OMSTREAM;
122 template <class T>
123 class BSMATRIX {
124 // hack.
125 friend class BSMATRIX<double>;
126 friend class BSMATRIX<std::complex<double> >;
127 private:
128 mutable bool* _changed; // flag: this node changed value
129 unsigned* _lownode; // lowest node connecting to this one
130 T* _space; // ptr to actual memory space used
131 T** _rowptr; // ptrs to col 0 of every row
132 T** _colptr; // ptrs to row 0 of every col
133 T** _diaptr; // ptrs to diagonal
134 unsigned _nzcount; // count of non-zero elements
135 unsigned _size; // # of rows and columns
136 T _zero; // always 0 but not const
137 T _trash; // depository for row and col 0, write only
138 T _min_pivot; // minimum pivot value
139 unsigned _bandwidth; // (0=diagonal)
140 std::vector<std::set<unsigned> > _adj;
141 std::vector<std::set<unsigned> > _adj_ordered;
142 public:
143 enum REAL {_REAL};
144 enum IMAG {_IMAG};
145 enum SUM {_SUM};
146 BSMATRIX(const BSMATRIX<T>&);
147 private:
148 explicit BSMATRIX(REAL, const BSMATRIX<std::complex<double> >&);
149 explicit BSMATRIX(IMAG, const BSMATRIX<std::complex<double> >&);
150 explicit BSMATRIX(SUM, const BSMATRIX<std::complex<double> >&);
151 void uninit();
152 void init(unsigned s=0);
153 T& subtract_dot_product(uint_t r, uint_t c, uint_t d);
154 T& subtract_dot_product(uint_t r, uint_t c, uint_t d, const T& in);
155 unsigned lownode(unsigned i)const {return _lownode[i];}
156 bool is_changed(unsigned n)const {return _changed[n];}
157 void set_changed(uint_t n, bool x = true)const {_changed[n] = x;}
158 public:
159 explicit BSMATRIX(unsigned ss=0);
160 ~BSMATRIX() {uninit();}
161 void reinit(unsigned ss=0) {uninit(); init(ss);}
162 //void clone(const BSMATRIX<T>&);
163 BSMATRIX<T>* copy()const // also copy contents
164 { return new BSMATRIX(*this); }
165 BSMATRIX<double> real()const
166 { return( BSMATRIX<double>(BSMATRIX< double >::_REAL, *this) ) ; }
167 BSMATRIX<double> imag()const
168 { return( BSMATRIX<double>(BSMATRIX< double >::_IMAG, *this) ) ; }
169 BSMATRIX<double> sum()const
170 { return( BSMATRIX<double>(BSMATRIX< double >::_SUM, *this) ) ; }
171 T* row(T*, unsigned);
172 T* col(T*, unsigned);
173 void iwant(unsigned, unsigned);
174 void iwant(unsigned*);
175 private:
176 void i_do_want(unsigned, unsigned);
177 int* _rcm;
178 void rcm(); // used by allocate.
179 public:
180 void unallocate();
181 void allocate(unsigned*nm=NULL);
182 void reallocate() {unallocate(); allocate();}
183 void set_min_pivot(double x) {_min_pivot = x;}
184 void zero();
185 void dezero(T& o);
186 unsigned size()const {return _size;}
187 double density();
188 inline T* rmul(T* b, const T* x)const; // returns A*x
189 T d(unsigned r, unsigned )const;
190 T s(unsigned r, unsigned c)const;
191 needed_t n(unsigned row, unsigned col)const;
192 private:
193 T u(unsigned r, unsigned c)const;
194 T l(unsigned r, unsigned c)const;
195 T& d(unsigned r, unsigned c);
196 T& u(unsigned r, unsigned c);
197 T& l(unsigned r, unsigned c);
198 T& m(unsigned r, unsigned c);
199 T& s(unsigned r, unsigned c);
200 public:
201 template <class S,class X>
202 friend S& operator<< ( S &o, const BSMATRIX<X>& m);
204 BSMATRIX& operator*=( const T& s);
205 BSMATRIX& operator+=( const BSMATRIX& s);
206 BSMATRIX& operator=( const BSMATRIX& s);
207 // BSMATRIX& operator-( BSMATRIX& s);
208 // template <class X>
209 // friend OMSTREAM& operator<< ( OMSTREAM &o, const BSMATRIX<X>& m);
210 void load_diagonal_point(uint_t i, T value);
211 void load_point(uint_t i, uint_t j, T value);
212 void load_couple(uint_t i, uint_t j, T value);
213 void load_symmetric(uint_t i, uint_t j, T value);
214 void load_asymmetric(uint_t r1, uint_t r2, uint_t c1, uint_t c2, T value);
216 void lu_decomp(const BSMATRIX<T>&, bool do_partial=false);
217 void lu_decomp();
218 void fbsub(T* v) const;
219 void fbsub(std::complex<T>* v) const;
220 void fbsub(T* x, const T* b, T* c ) const;
221 T* fbsub(T* x, const T* b ) const { fbsub(x,b,x); return x; }
222 void fbsubt(T* v) const;
223 public:
224 void sink_forward(unsigned* nm);
225 void sink_reverse(unsigned* nm);
226 public: //eigenvalue stuff
227 void augment(T*, T*row=0);
228 void deaugment();
230 /*--------------------------------------------------------------------------*/
231 // private implementations
232 /*--------------------------------------------------------------------------*/
233 template <class T>
234 void BSMATRIX<T>::uninit()
236 unallocate();
237 delete [] _lownode;
238 _lownode = NULL;
239 delete [] _changed;
240 _changed = NULL;
242 /*--------------------------------------------------------------------------*/
243 template <class T>
244 void BSMATRIX<T>::init(unsigned ss)
246 assert(!_lownode);
247 assert(!_colptr);
248 assert(!_rowptr);
249 assert(!_diaptr);
250 assert(!_space);
252 assert(_zero == 0.);
253 _min_pivot = _trash = 0.;
254 _nzcount = 0;
255 _size = ss;
256 _lownode = new unsigned[size()+1];
257 assert(_lownode);
258 for (unsigned ii = 0; ii <= size(); ++ii) {
259 _lownode[ii] = ii;
261 _changed = new bool[size()+1];
262 assert(_changed);
263 for (unsigned ii = 0; ii <= size(); ++ii) {
264 set_changed(ii, false);
267 _adj.clear();
268 _adj.resize(size()+1);
270 /*--------------------------------------------------------------------------*/
271 template <class T>
272 T& BSMATRIX<T>::subtract_dot_product(uint_t rr, uint_t cc, uint_t dd)
274 assert(_lownode);
275 uint_t kk = std::max(_lownode[rr], _lownode[cc]);
276 assert(dd>=kk);
277 unsigned len = unsigned(dd - kk);
278 T& dot = m(rr, cc);
279 if (len > 0) {
280 T* row_ = &(l(rr,kk));
281 T* col_ = &(u(kk,cc));
282 /* for (ii = kk; ii < dd; ++ii) */
283 for (unsigned ii = 0; ii < len; ++ii) {
284 dot -= *(row_-ii) * col_[ii];
286 }else{
288 return dot;
290 /*--------------------------------------------------------------------------*/
291 template <class T>
292 T& BSMATRIX<T>::subtract_dot_product(uint_t rr, uint_t cc, uint_t dd, const T& in)
294 assert(_lownode);
295 unsigned kk = std::max(_lownode[rr], _lownode[cc]);
296 int len = int(dd) - int(kk);
297 T& dot = m(rr, cc);
298 dot = in;
299 if (len > 0) {
300 T* row_ = &(l(rr,kk));
301 T* col_ = &(u(kk,cc));
302 /* for (ii = kk; ii < dd; ++ii) */
303 for (int ii = 0; ii < len; ++ii) {
304 dot -= *(row_-ii) * col_[ii];
306 }else{
308 return dot;
310 /*--------------------------------------------------------------------------*/
311 // public implementations
312 /*--------------------------------------------------------------------------*/
313 template <class T>
314 BSMATRIX<T>::BSMATRIX(unsigned ss)
315 :_changed(NULL),
316 _lownode(NULL),
317 _space(NULL),
318 _rowptr(NULL),
319 _colptr(NULL),
320 _diaptr(NULL),
321 _nzcount(0),
322 _size(ss),
323 _zero(0.),
324 _trash(0.),
325 _min_pivot(0.),
326 _bandwidth(0)
328 init(ss);
330 /*--------------------------------------------------------------------------*/
331 #if 0
332 /* clone: copy to self the structure of another BSMATRIX
333 * this does not copy the values stored in the matrix
335 template <class T>
336 void BSMATRIX<T>::clone(const BSMATRIX<T> & aa)
337 {untested();
338 reinit(aa.size());
339 for (int ii = 0; ii <= size(); ++ii) {untested();
340 _lownode[ii] = aa.lownode(ii);
343 #endif
344 /*--------------------------------------------------------------------------*/
345 /* iwant: indicate that "iwant" to allocate this spot in the matrix
347 template <class T>
348 void BSMATRIX<T>::iwant(unsigned node1, unsigned node2)
350 trace2("BSMATRIX::iwant", node1, node2);
351 assert(_lownode);
352 assert(node1 <= size());
353 assert(node2 <= size());
355 // _adj.resize( std::max(std::max(node1, node2), unsigned(_adj.size())));
356 assert(node1 < _adj.size());
357 assert(node2 < _adj.size());
358 _adj[node1].insert(node2);
359 _adj[node2].insert(node1);
362 /*--------------------------------------*/
363 template <class T>
364 void BSMATRIX<T>::iwant(unsigned* nm)
366 _adj_ordered.clear();
367 _adj_ordered.resize(_adj.size());
368 for( unsigned j=0; j<size(); ++j ){
369 for(std::set<unsigned>::const_iterator ii=_adj[j].begin();
370 ii != _adj[j].end(); ++ii )
372 i_do_want(nm[j],nm[*ii]);
373 _adj_ordered[nm[j]].insert(nm[*ii]);
374 _adj_ordered[nm[*ii]].insert(nm[j]);
378 /*--------------------------------------*/
379 // i really want the nodes (former iwant)
380 template <class T>
381 void BSMATRIX<T>::i_do_want(unsigned node1, unsigned node2)
383 if (node1 <= 0 || node2 <= 0) {
384 // node 0 is ground, and doesn't count as a connection
385 // negative is invalid, not used but still may be in a node list
386 }else if (node1 < _lownode[node2]) {
387 _lownode[node2]=node1;
388 }else if (node2 < _lownode[node1]) {
389 _lownode[node1]=node2;
390 }else{
393 /*--------------------------------------------------------------------------*/
394 template <class T>
395 void BSMATRIX<T>::unallocate()
397 assert (_zero == 0.);
398 delete [] _rowptr;
399 delete [] _colptr;
400 delete [] _diaptr;
401 delete [] _space;
403 _rowptr = _colptr = _diaptr = NULL;
404 _space = NULL;
406 /*--------------------------------------------------------------------------*/
407 /* allocate: really get the space to work
408 * hmm maybe pass nm here?
410 template <class T>
411 void BSMATRIX<T>::allocate(unsigned* nm)
413 if(nm)incomplete();
414 assert(_lownode);
415 assert(!_colptr);
416 assert(!_rowptr);
417 assert(!_diaptr);
418 assert(!_space);
420 _nzcount = 0;
421 for (unsigned ii = 0; ii <= size(); ++ii) {
422 assert (ii >= _lownode[ii]);
423 _nzcount += 2 * unsigned(ii - _lownode[ii]) + 1;
426 _colptr = new T*[size()+1];
427 _rowptr = new T*[size()+1];
428 _diaptr = new T*[size()+1];
429 trace1("BSMATRIX::allocate", _nzcount);
430 _space = new T[_nzcount];
432 assert(_colptr);
433 assert(_rowptr);
434 assert(_diaptr);
436 zero();
439 T* point = _space;
440 for (unsigned ii = 0; ii <= size(); ++ii) {
441 _colptr[ii] = point - (int)_lownode[ii];
442 _rowptr[ii] = _colptr[ii] + 2*ii;
443 _diaptr[ii] = _colptr[ii] + ii;
444 point += 2 * ((int)ii - (int)_lownode[ii]) + 1;
448 /*--------------------------------------------------------------------------*/
449 /* zero: wipe the whole array
451 template <class T>
452 void BSMATRIX<T>::zero()
454 assert(_space);
455 assert(_zero == 0.);
456 _trash = 0.;
457 std::fill_n(_space, _nzcount, 0.);
459 /*--------------------------------------------------------------------------*/
460 /* dezero: make sure(?) the diagonal is non-zero
462 template <class T>
463 void BSMATRIX<T>::dezero(T& offset)
465 for (unsigned ii = 1; ii <= size(); ++ii) {
466 d(ii,ii) += offset;
469 /*--------------------------------------------------------------------------*/
470 template <class T>
471 double BSMATRIX<T>::density()
473 if (size() > 0) {
474 assert(_lownode);
475 _nzcount = 0;
476 for (unsigned ii = 0; ii <= size(); ++ii) {
477 _nzcount += 2 * (ii - _lownode[ii]) + 1;
479 return static_cast<double>(_nzcount-1)/(static_cast<double>(size())*size());
480 }else{
481 return 0;
484 /*--------------------------------------------------------------------------*/
485 /* d: fast matrix entry access
486 * It is known that the entry is valid and on the diagonal
488 template <class T>
489 T BSMATRIX<T>::d(unsigned r, unsigned c) const
491 USE(c);
492 assert(_diaptr);
493 assert(r == c);
494 assert(0 <= r);
495 assert(r <= _size);
497 return *(_diaptr[r]);
499 /*--------------------------------------------------------------------------*/
500 /* d: as above, but lvalue */
501 template <class T>
502 T& BSMATRIX<T>::d(unsigned r, unsigned c)
504 USE(c);
505 assert(_diaptr);
506 assert(r == c); USE(c);
507 assert(r);
508 assert(r <= _size);
510 return *(_diaptr[r]);
512 /*--------------------------------------------------------------------------*/
513 /* u: fast matrix entry access
514 * It is known that the entry is valid and in the upper triangle (or diagonal)
516 template <class T>
517 T BSMATRIX<T>::u(unsigned r, unsigned c) const
519 assert(_colptr);
520 assert(_lownode);
521 assert(0 < r);
522 assert(r <= c);
523 assert(c <= _size);
524 assert(1 <= _lownode[c]);
525 assert(_lownode[c] <= r);
527 return _colptr[c][r];
529 /*--------------------------------------------------------------------------*/
530 /* u: as above, but lvalue */
531 template <class T>
532 T& BSMATRIX<T>::u(unsigned r, unsigned c)
534 assert(_colptr);
535 assert(_lownode);
536 assert(r);
537 assert(r <= c);
538 //assert(c <= _size);
539 assert(1 <= _lownode[c]);
540 assert(_lownode[c] <= r);
542 return _colptr[c][r];
544 /*--------------------------------------------------------------------------*/
545 /* l: fast matrix entry access
546 * It is known that the entry is valid and in the lower triangle not diagonal
548 template <class T>
549 T BSMATRIX<T>::l(unsigned r, unsigned c) const
551 assert(_rowptr);
552 assert(_lownode);
553 assert(0 < c);
554 assert(c <= r);
555 assert(r <= _size);
556 assert(1 <= _lownode[r]);
557 assert(_lownode[r] <= c);
559 return *(_rowptr[r]-c);
561 /*--------------------------------------------------------------------------*/
562 /* l: as above, but lvalue */
563 template <class T>
564 T& BSMATRIX<T>::l(unsigned r, unsigned c)
566 assert(_rowptr);
567 assert(_lownode);
568 assert(0 < c);
569 assert(c < r);
570 assert(r <= _size);
571 assert(1 <= _lownode[r]);
572 assert(_lownode[r] <= c);
574 return *(_rowptr[r]-c);
576 /*--------------------------------------------------------------------------*/
577 /* m: semi-fast matrix entry access
578 * It is known that the entry refers to a valid location
579 * but it is not known whether lower, upper, or diagonal
581 template <class T>
582 T& BSMATRIX<T>::m(unsigned r, unsigned c)
584 if (c>=r) {
585 return u(r,c);
586 }else{
587 return l(r,c);
590 /*--------------------------------------------------------------------------*/
591 /* s: general matrix entry access (read-only)
592 * It is known that the location is strictly in bounds,
593 * but it is not known whether the location actually exists.
594 * If access is attempted to a non-allocated location,
595 * it returns a reference to a shared zero variable.
596 * Writing to this zero is not prohibited,
597 * but will corrupt the matrix in a known and testable way.
598 * If access is attempted to row 0 or column 0,
599 * it returns a reference to a shared trash variable.
600 * Writing to trash is allowed and encouraged,
601 * but reading it gives a number not useful for anything.
603 template <class T>
604 T BSMATRIX<T>::s(unsigned row, unsigned col)const
605 {itested();
606 assert(_lownode);
607 // assert(0 <= col);
608 assert(col <= size());
609 // assert(0 <= row);
610 assert(row <= size());
611 assert(_zero == 0.);
613 if (col == row) {itested();
614 return d(row, col);
615 }else if (col > row) {itested(); /* above the diagonal */
616 if (row == 0) {untested();
617 return _trash;
618 }else if (row < _lownode[col]) {
619 return _zero;
620 }else{itested();
621 return u(row, col);
623 }else{itested(); /* below the diagonal */
624 assert(col < row);
625 if (col == 0) {
626 return _trash;
627 }else if (col < _lownode[row]) {
628 return _zero;
629 }else{
630 return (l(row,col));
633 unreachable();
635 /*--------------------------------------------------------------------------*/
636 // the entry is allocated (non-zero)
637 template <class T>
638 needed_t BSMATRIX<T>::n(unsigned row, unsigned col)const
640 assert(_lownode);
641 // assert(0 <= col);
642 assert(col <= size());
643 // assert(0 <= row);
644 assert(row <= size());
645 assert(_zero == 0.);
647 if (_adj_ordered[row].find(col) != _adj_ordered[row].end()){
648 return nYES;
651 if (col == row) {
652 return nYES;
653 }else if (col > row) { /* above the diagonal */
654 if (row == 0) {
655 return nNO;
656 }else if (row < _lownode[col]) {
657 return nNO;
658 }else{
659 return nFILL;
661 }else{ /* below the diagonal */
662 assert(col < row);
663 if (col == 0) {
664 return nNO;
665 }else if (col < _lownode[row]) {
666 return nNO;
667 }else{
668 return nFILL;
671 unreachable();
673 /*--------------------------------------------------------------------------*/
674 // rw access.
675 template <class T>
676 T& BSMATRIX<T>::s(unsigned row, unsigned col)
678 assert(_lownode);
679 // assert(0 <= col);
680 assert(col <= size());
681 // assert(0 <= row);
682 assert(row <= size());
683 assert(_zero == 0.);
685 if (col == row) {
686 return d(row,col);
687 }else if (col > row) { /* above the diagonal */
688 if (row == 0) {
689 return _trash;
690 }else if (row < _lownode[col]) {
691 return _zero;
692 }else{
693 return (u(row,col));
695 }else{ /* below the diagonal */
696 assert(col < row);
697 if (col == 0) {
698 return _trash;
699 }else if (col < _lownode[row]) {
700 return _zero;
701 }else{untested();
702 return l(row, col);
705 unreachable();
707 /*--------------------------------------------------------------------------*/
708 template <class T>
709 void BSMATRIX<T>::load_point(unsigned i, unsigned j, T value)
710 {itested();
711 if (i > 0 && j > 0) {itested();
712 set_changed(j);
713 set_changed(i);
714 m(i,j) += value;
715 }else{itested();
718 /*--------------------------------------------------------------------------*/
719 // load_point(i, i, value);
720 template <class T>
721 void BSMATRIX<T>::load_diagonal_point(uint_t i, T value)
723 if (i > 0) {
724 set_changed(i);
725 d(i,i) += value;
726 }else{untested();
729 /*--------------------------------------------------------------------------*/
730 // load_point(i, j, -value);
731 // load_point(j, i, -value);
732 template <class T>
733 void BSMATRIX<T>::load_couple(uint_t i, uint_t j, T value)
735 if (j > 0) {
736 set_changed(j);
737 if (i > 0) {
738 set_changed(i);
739 m(i,j) -= value;
740 m(j,i) -= value;
741 }else{
743 }else{untested();
746 /*--------------------------------------------------------------------------*/
747 // load_point(i, i, value); or load_diagonal_point(i, value);
748 // load_point(j, j, value); or load_diagonal_point(j, value);
749 // load_point(i, j, -value);
750 // load_point(j, i, -value);
751 template <class T>
752 void BSMATRIX<T>::load_symmetric(uint_t i, uint_t j, T value)
754 if (j > 0) {
755 set_changed(j);
756 d(j,j) += value;
757 if (i > 0) {
758 set_changed(i);
759 d(i,i) += value;
760 m(i,j) -= value;
761 m(j,i) -= value;
762 }else{
764 }else if (i > 0) {
765 set_changed(i);
766 d(i,i) += value;
767 }else{
770 /*--------------------------------------------------------------------------*/
771 // load_point(r1, c1, value);
772 // load_point(r2, c2, value);
773 // load_point(r1, c2, -value);
774 // load_point(r2, c1, -value);
775 template <class T>
776 void BSMATRIX<T>::load_asymmetric(uint_t r1,uint_t r2,uint_t c1,uint_t c2,T value)
778 set_changed(c1);
779 set_changed(c2);
780 if (r1 > 0) {
781 set_changed(r1);
782 if (c1 > 0) {
783 m(r1,c1) += value;
784 }else{
786 if (c2 > 0) {
787 m(r1,c2) -= value;
788 }else{
790 }else{
792 if (r2 > 0) {
793 set_changed(r2);
794 if (c1 > 0) {
795 m(r2,c1) -= value;
796 }else{
798 if (c2 > 0) {
799 m(r2,c2) += value;
800 }else{
802 }else{
805 /*--------------------------------------------------------------------------*/
806 template <class T>
807 void BSMATRIX<T>::lu_decomp(const BSMATRIX<T>& aa, bool do_partial)
809 unsigned prop = 0; /* change propagation indicator */
810 assert(_lownode);
811 assert(aa._lownode);
812 assert(aa.size() == size());
813 for (unsigned mm = 1; mm <= size(); ++mm) {
814 assert(aa.lownode(mm) == _lownode[mm]);
815 unsigned bn = _lownode[mm];
816 if (!do_partial || aa.is_changed(mm) || bn <= prop) {
817 aa.set_changed(mm, false);
818 prop = mm;
819 if (bn < mm) {
820 prop = mm;
821 u(bn,mm) = aa.u(bn,mm) / d(bn,bn);
822 for (unsigned ii = bn+1; ii<mm; ii++) {
823 /* u(ii,mm) = (aa.u(ii,mm) - dot(ii,mm,ii)) / d(ii,ii); */
824 subtract_dot_product(ii,mm,ii,aa.u(ii,mm)) /= d(ii,ii);
826 l(mm,bn) = aa.l(mm,bn);
827 for (unsigned jj = bn+1; jj<mm; jj++) {
828 /* l(mm,jj) = aa.l(mm,jj) - dot(mm,jj,jj); */
829 subtract_dot_product(mm,jj,jj,aa.l(mm,jj));
831 { /* jj == mm */
832 /* d(mm,mm) = aa.d(mm,mm) - dot(mm,mm,mm); then test */
833 if (subtract_dot_product(mm,mm,mm,aa.d(mm,mm)) == 0.) {
834 error(bWARNING, "open circuit: internal node %u\n", mm);
835 d(mm,mm) = _min_pivot;
836 }else{
839 }else{ /* bn == mm */
840 d(mm,mm) = aa.d(mm,mm);
841 if (d(mm,mm)==0.) {untested();
842 d(mm,mm) = _min_pivot;
843 }else{
846 }else{
850 /*--------------------------------------------------------------------------*/
851 template <class T>
852 void BSMATRIX<T>::lu_decomp()
854 assert(_lownode);
855 for (unsigned mm = 1; mm <= size(); ++mm) {
856 unsigned bn = _lownode[mm];
857 if (bn < mm) {
858 u(bn,mm) /= d(bn,bn);
859 for (unsigned ii =bn+1; ii<mm; ii++) {
860 /* (m(ii,mm) -= dot(ii,mm,ii)) /= d(ii,ii); */
861 subtract_dot_product(ii,mm,ii) /= d(ii,ii);
863 for (unsigned jj = bn+1; jj<mm; jj++) {
864 /* m(mm,jj) -= dot(mm,jj,jj); */
865 subtract_dot_product(mm,jj,jj);
867 { /* jj == mm */
868 /* m(mm,mm) -= dot(mm,mm,mm); then test */
869 if (subtract_dot_product(mm,mm,mm) == 0.) {
870 error(bWARNING, "open circuit: internal node %u\n", mm);
871 d(mm,mm) = _min_pivot;
872 }else{
875 }else{ /* bn == mm */
876 if (d(mm,mm)==0.) {
877 d(mm,mm) = _min_pivot;
878 }else{
883 /*--------------------------------------------------------------------------*/
884 /* fbsub: forward and back sub, shared storage
885 * v = right side vector, changed in place to solution vector
887 template <class T>
888 void BSMATRIX<T>::fbsub(T* v) const
890 assert(_lownode);
891 assert(v);
893 for (unsigned ii = 1; ii <= size(); ++ii) { /* forward substitution */
894 for (unsigned jj = _lownode[ii]; jj < ii; ++jj) {
895 v[ii] -= l(ii,jj) * v[jj];
897 v[ii] /= d(ii,ii);
900 for (unsigned jj = size(); jj > 1; --jj) { /* back substitution */
901 for (unsigned ii = _lownode[jj]; ii < jj; ++ii) {
902 v[ii] -= u(ii,jj) * v[jj];
906 /*--------------------------------------------------------------------------*/
907 /* fbsub: forward and back sub, separate storage
908 * x = solution vector
909 * b = right side vector
910 * c = intermediate vector after fwd sub
912 template <class T>
913 void BSMATRIX<T>::fbsub(T* x, const T* b, T* c) const
915 assert(_lownode);
916 assert(x);
917 assert(b);
918 assert(c);
921 unsigned ii = 1;
922 for ( ; ii <= size(); ++ii) {
923 if (b[ii] != 0.) {
924 break;
925 }else{
927 c[ii] = 0.;
930 unsigned first_nz = ii;
931 for ( ; ii <= size(); ++ii) { /* forward substitution */
932 unsigned low_node = std::max(_lownode[ii], first_nz);
933 c[ii] = b[ii];
934 for (unsigned jj = low_node; jj < ii; ++jj) {
935 c[ii] -= l(ii,jj) * c[jj];
937 c[ii] /= d(ii,ii);
941 notstd::copy_n(c, size()+1, x);
943 for (unsigned jj = size(); jj > 1; --jj) { /* back substitution */
944 for (unsigned ii = _lownode[jj]; ii < jj; ++ii) {
945 x[ii] -= u(ii,jj) * x[jj];
948 x[0] = 0.;
949 // index starts at 1, but node 0 is ground
950 // x[0]==0 eliminates a lot of "if" statements
952 /*--------------------------------------------------------------------------*/
953 template<class T>
954 BSMATRIX<T>::BSMATRIX(const BSMATRIX<T>& m) :
955 _changed(new bool[m.size()+1]),
956 _lownode(new unsigned[m.size()+1]),
957 _space(new T[m._nzcount]),
958 _rowptr(new T*[m._size+1]),
959 _colptr(new T*[m._size+1]),
960 _diaptr(new T*[m._size+1]),
961 _nzcount(m._nzcount),
962 _size(m._size),
963 _zero(0),
964 _trash(m._trash),
965 _min_pivot(m._min_pivot)
967 memcpy(_changed,m._changed, (_size+1) * sizeof(bool) );
968 memcpy(_lownode,m._lownode, (_size+1) * sizeof(unsigned) );
969 memcpy(_space,m._space, (_nzcount) * sizeof(T));
971 for(unsigned i=0; i<=_size; i++){
972 _rowptr[i]= _space - intptr_t(m._space - m._rowptr[i]);
973 _colptr[i]= _space - intptr_t(m._space - m._colptr[i]);
974 _diaptr[i]= _space - intptr_t(m._space - m._diaptr[i]);
979 /*--------------------------------------------------------------------------*/
980 // template <class X, class Y>
981 //Y& operator<< ( Y &o, const BSMATRIX<X>& m);
983 //template <class X>
984 //OMSTREAM& operator<< ( OMSTREAM &o, const BSMATRIX<X>& m);
985 template<>
986 void BSMATRIX<double>::sink_forward(unsigned* nm);
987 template<>
988 void BSMATRIX<double>::sink_reverse(unsigned* nm);
989 /*--------------------------------------------------------------------------*/
990 /* fbsubt: forward and back substitution with implicitly transposed matrix Ut Lt x = v
991 * v = right side vector, changed in place to solution vector
992 * GS:
993 * this method s used to solve system A_t X = B (_t - transposed)
994 * which corresponds to adjoint system
995 * (LU)_t then transforms to U_t L_t
996 * added: Gennadiy Serdyuk <gserdyuk@gserdyuk.com>
998 template <class T>
999 void BSMATRIX<T>::fbsubt(T* v) const
1000 {untested();
1001 assert(_lownode);
1002 assert(v);
1004 // forward substitution
1005 for (unsigned ii = 1; ii <= size(); ++ii) {untested();
1006 for (unsigned jj = _lownode[ii]; jj < ii; ++jj) {untested();
1007 v[ii] -= u(jj,ii) * v [jj];
1011 // back substitution
1012 for (unsigned jj = size(); jj > 1; --jj) {untested();
1013 v[jj] /= d(jj,jj);
1014 for (unsigned ii = _lownode[jj]; ii < jj; ++ii) {untested();
1015 v[ii] -= l(jj,ii) * v[jj];
1018 v[1]/=d(1,1);
1020 /*--------------------------------------------------------------------------*/
1021 // apply real matrix to complex vector.
1022 template<class T>
1023 void BSMATRIX<T>::fbsub(std::complex<T>* v)const
1025 T part[size()+1];
1026 for(unsigned i=0; i<=size(); ++i){
1027 part[i] = v[i].real();
1029 fbsub(part);
1030 for(unsigned i=0; i<=size(); ++i){
1031 v[i].real(part[i]);
1032 part[i] = v[i].imag();
1034 fbsub(part);
1035 for(unsigned i=0; i<=size(); ++i){
1036 v[i].imag(part[i]);
1039 /*--------------------------------------------------------------------------*/
1040 #endif
1042 // vim:ts=8:sw=2:noet: