]> www.ginac.de Git - ginac.git/blob - ginac/matrix.cpp
- fixed bug in multiply_lcm() (see paranoia_check9)
[ginac.git] / ginac / matrix.cpp
1 /** @file matrix.cpp
2  *
3  *  Implementation of symbolic matrices */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <algorithm>
24 #include <stdexcept>
25
26 #include "matrix.h"
27 #include "archive.h"
28 #include "utils.h"
29 #include "debugmsg.h"
30
31 #ifndef NO_NAMESPACE_GINAC
32 namespace GiNaC {
33 #endif // ndef NO_NAMESPACE_GINAC
34
35 GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic)
36
37 //////////
38 // default constructor, destructor, copy constructor, assignment operator
39 // and helpers:
40 //////////
41
42 // public
43
44 /** Default ctor.  Initializes to 1 x 1-dimensional zero-matrix. */
45 matrix::matrix()
46     : inherited(TINFO_matrix), row(1), col(1)
47 {
48     debugmsg("matrix default constructor",LOGLEVEL_CONSTRUCT);
49     m.push_back(_ex0());
50 }
51
52 matrix::~matrix()
53 {
54     debugmsg("matrix destructor",LOGLEVEL_DESTRUCT);
55 }
56
57 matrix::matrix(const matrix & other)
58 {
59     debugmsg("matrix copy constructor",LOGLEVEL_CONSTRUCT);
60     copy(other);
61 }
62
63 const matrix & matrix::operator=(const matrix & other)
64 {
65     debugmsg("matrix operator=",LOGLEVEL_ASSIGNMENT);
66     if (this != &other) {
67         destroy(1);
68         copy(other);
69     }
70     return *this;
71 }
72
73 // protected
74
75 void matrix::copy(const matrix & other)
76 {
77     inherited::copy(other);
78     row=other.row;
79     col=other.col;
80     m=other.m;  // use STL's vector copying
81 }
82
83 void matrix::destroy(bool call_parent)
84 {
85     if (call_parent) inherited::destroy(call_parent);
86 }
87
88 //////////
89 // other constructors
90 //////////
91
92 // public
93
94 /** Very common ctor.  Initializes to r x c-dimensional zero-matrix.
95  *
96  *  @param r number of rows
97  *  @param c number of cols */
98 matrix::matrix(unsigned r, unsigned c)
99     : inherited(TINFO_matrix), row(r), col(c)
100 {
101     debugmsg("matrix constructor from unsigned,unsigned",LOGLEVEL_CONSTRUCT);
102     m.resize(r*c, _ex0());
103 }
104
105 // protected
106
107 /** Ctor from representation, for internal use only. */
108 matrix::matrix(unsigned r, unsigned c, const exvector & m2)
109     : inherited(TINFO_matrix), row(r), col(c), m(m2)
110 {
111     debugmsg("matrix constructor from unsigned,unsigned,exvector",LOGLEVEL_CONSTRUCT);
112 }
113
114 //////////
115 // archiving
116 //////////
117
118 /** Construct object from archive_node. */
119 matrix::matrix(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
120 {
121     debugmsg("matrix constructor from archive_node", LOGLEVEL_CONSTRUCT);
122     if (!(n.find_unsigned("row", row)) || !(n.find_unsigned("col", col)))
123         throw (std::runtime_error("unknown matrix dimensions in archive"));
124     m.reserve(row * col);
125     for (unsigned int i=0; true; i++) {
126         ex e;
127         if (n.find_ex("m", e, sym_lst, i))
128             m.push_back(e);
129         else
130             break;
131     }
132 }
133
134 /** Unarchive the object. */
135 ex matrix::unarchive(const archive_node &n, const lst &sym_lst)
136 {
137     return (new matrix(n, sym_lst))->setflag(status_flags::dynallocated);
138 }
139
140 /** Archive the object. */
141 void matrix::archive(archive_node &n) const
142 {
143     inherited::archive(n);
144     n.add_unsigned("row", row);
145     n.add_unsigned("col", col);
146     exvector::const_iterator i = m.begin(), iend = m.end();
147     while (i != iend) {
148         n.add_ex("m", *i);
149         i++;
150     }
151 }
152
153 //////////
154 // functions overriding virtual functions from bases classes
155 //////////
156
157 // public
158
159 basic * matrix::duplicate() const
160 {
161     debugmsg("matrix duplicate",LOGLEVEL_DUPLICATE);
162     return new matrix(*this);
163 }
164
165 void matrix::print(ostream & os, unsigned upper_precedence) const
166 {
167     debugmsg("matrix print",LOGLEVEL_PRINT);
168     os << "[[ ";
169     for (unsigned r=0; r<row-1; ++r) {
170         os << "[[";
171         for (unsigned c=0; c<col-1; ++c) {
172             os << m[r*col+c] << ",";
173         }
174         os << m[col*(r+1)-1] << "]], ";
175     }
176     os << "[[";
177     for (unsigned c=0; c<col-1; ++c) {
178         os << m[(row-1)*col+c] << ",";
179     }
180     os << m[row*col-1] << "]] ]]";
181 }
182
183 void matrix::printraw(ostream & os) const
184 {
185     debugmsg("matrix printraw",LOGLEVEL_PRINT);
186     os << "matrix(" << row << "," << col <<",";
187     for (unsigned r=0; r<row-1; ++r) {
188         os << "(";
189         for (unsigned c=0; c<col-1; ++c) {
190             os << m[r*col+c] << ",";
191         }
192         os << m[col*(r-1)-1] << "),";
193     }
194     os << "(";
195     for (unsigned c=0; c<col-1; ++c) {
196         os << m[(row-1)*col+c] << ",";
197     }
198     os << m[row*col-1] << "))";
199 }
200
201 /** nops is defined to be rows x columns. */
202 unsigned matrix::nops() const
203 {
204     return row*col;
205 }
206
207 /** returns matrix entry at position (i/col, i%col). */
208 ex matrix::op(int i) const
209 {
210     return m[i];
211 }
212
213 /** returns matrix entry at position (i/col, i%col). */
214 ex & matrix::let_op(int i)
215 {
216     return m[i];
217 }
218
219 /** expands the elements of a matrix entry by entry. */
220 ex matrix::expand(unsigned options) const
221 {
222     exvector tmp(row*col);
223     for (unsigned i=0; i<row*col; ++i) {
224         tmp[i]=m[i].expand(options);
225     }
226     return matrix(row, col, tmp);
227 }
228
229 /** Search ocurrences.  A matrix 'has' an expression if it is the expression
230  *  itself or one of the elements 'has' it. */
231 bool matrix::has(const ex & other) const
232 {
233     GINAC_ASSERT(other.bp!=0);
234     
235     // tautology: it is the expression itself
236     if (is_equal(*other.bp)) return true;
237     
238     // search all the elements
239     for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) {
240         if ((*r).has(other)) return true;
241     }
242     return false;
243 }
244
245 /** evaluate matrix entry by entry. */
246 ex matrix::eval(int level) const
247 {
248     debugmsg("matrix eval",LOGLEVEL_MEMBER_FUNCTION);
249     
250     // check if we have to do anything at all
251     if ((level==1)&&(flags & status_flags::evaluated)) {
252         return *this;
253     }
254     
255     // emergency break
256     if (level == -max_recursion_level) {
257         throw (std::runtime_error("matrix::eval(): recursion limit exceeded"));
258     }
259     
260     // eval() entry by entry
261     exvector m2(row*col);
262     --level;    
263     for (unsigned r=0; r<row; ++r) {
264         for (unsigned c=0; c<col; ++c) {
265             m2[r*col+c] = m[r*col+c].eval(level);
266         }
267     }
268     
269     return (new matrix(row, col, m2))->setflag(status_flags::dynallocated |
270                                                status_flags::evaluated );
271 }
272
273 /** evaluate matrix numerically entry by entry. */
274 ex matrix::evalf(int level) const
275 {
276     debugmsg("matrix evalf",LOGLEVEL_MEMBER_FUNCTION);
277         
278     // check if we have to do anything at all
279     if (level==1) {
280         return *this;
281     }
282     
283     // emergency break
284     if (level == -max_recursion_level) {
285         throw (std::runtime_error("matrix::evalf(): recursion limit exceeded"));
286     }
287     
288     // evalf() entry by entry
289     exvector m2(row*col);
290     --level;
291     for (unsigned r=0; r<row; ++r) {
292         for (unsigned c=0; c<col; ++c) {
293             m2[r*col+c] = m[r*col+c].evalf(level);
294         }
295     }
296     return matrix(row, col, m2);
297 }
298
299 // protected
300
301 int matrix::compare_same_type(const basic & other) const
302 {
303     GINAC_ASSERT(is_exactly_of_type(other, matrix));
304     const matrix & o=static_cast<matrix &>(const_cast<basic &>(other));
305     
306     // compare number of rows
307     if (row != o.rows()) {
308         return row < o.rows() ? -1 : 1;
309     }
310     
311     // compare number of columns
312     if (col != o.cols()) {
313         return col < o.cols() ? -1 : 1;
314     }
315     
316     // equal number of rows and columns, compare individual elements
317     int cmpval;
318     for (unsigned r=0; r<row; ++r) {
319         for (unsigned c=0; c<col; ++c) {
320             cmpval=((*this)(r,c)).compare(o(r,c));
321             if (cmpval!=0) return cmpval;
322         }
323     }
324     // all elements are equal => matrices are equal;
325     return 0;
326 }
327
328 //////////
329 // non-virtual functions in this class
330 //////////
331
332 // public
333
334 /** Sum of matrices.
335  *
336  *  @exception logic_error (incompatible matrices) */
337 matrix matrix::add(const matrix & other) const
338 {
339     if (col != other.col || row != other.row) {
340         throw (std::logic_error("matrix::add(): incompatible matrices"));
341     }
342     
343     exvector sum(this->m);
344     exvector::iterator i;
345     exvector::const_iterator ci;
346     for (i=sum.begin(), ci=other.m.begin();
347          i!=sum.end();
348          ++i, ++ci) {
349         (*i) += (*ci);
350     }
351     return matrix(row,col,sum);
352 }
353
354 /** Difference of matrices.
355  *
356  *  @exception logic_error (incompatible matrices) */
357 matrix matrix::sub(const matrix & other) const
358 {
359     if (col != other.col || row != other.row) {
360         throw (std::logic_error("matrix::sub(): incompatible matrices"));
361     }
362     
363     exvector dif(this->m);
364     exvector::iterator i;
365     exvector::const_iterator ci;
366     for (i=dif.begin(), ci=other.m.begin();
367          i!=dif.end();
368          ++i, ++ci) {
369         (*i) -= (*ci);
370     }
371     return matrix(row,col,dif);
372 }
373
374 /** Product of matrices.
375  *
376  *  @exception logic_error (incompatible matrices) */
377 matrix matrix::mul(const matrix & other) const
378 {
379     if (col != other.row) {
380         throw (std::logic_error("matrix::mul(): incompatible matrices"));
381     }
382     
383     exvector prod(row*other.col);
384     for (unsigned i=0; i<row; ++i) {
385         for (unsigned j=0; j<other.col; ++j) {
386             for (unsigned l=0; l<col; ++l) {
387                 prod[i*other.col+j] += m[i*col+l] * other.m[l*other.col+j];
388             }
389         }
390     }
391     return matrix(row, other.col, prod);
392 }
393
394 /** operator() to access elements.
395  *
396  *  @param ro row of element
397  *  @param co column of element 
398  *  @exception range_error (index out of range) */
399 const ex & matrix::operator() (unsigned ro, unsigned co) const
400 {
401     if (ro<0 || ro>=row || co<0 || co>=col) {
402         throw (std::range_error("matrix::operator(): index out of range"));
403     }
404     
405     return m[ro*col+co];
406 }
407
408 /** Set individual elements manually.
409  *
410  *  @exception range_error (index out of range) */
411 matrix & matrix::set(unsigned ro, unsigned co, ex value)
412 {
413     if (ro<0 || ro>=row || co<0 || co>=col) {
414         throw (std::range_error("matrix::set(): index out of range"));
415     }
416     
417     ensure_if_modifiable();
418     m[ro*col+co]=value;
419     return *this;
420 }
421
422 /** Transposed of an m x n matrix, producing a new n x m matrix object that
423  *  represents the transposed. */
424 matrix matrix::transpose(void) const
425 {
426     exvector trans(col*row);
427     
428     for (unsigned r=0; r<col; ++r) {
429         for (unsigned c=0; c<row; ++c) {
430             trans[r*row+c] = m[c*col+r];
431         }
432     }
433     return matrix(col,row,trans);
434 }
435
436 /* Determiant of purely numeric matrix, using pivoting. This routine is only
437  * called internally by matrix::determinant(). */
438 ex determinant_numeric(const matrix & M)
439 {
440     GINAC_ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
441     matrix tmp(M);
442     ex det=_ex1();
443     ex piv;
444     
445     for (unsigned r1=0; r1<M.rows(); ++r1) {
446         int indx = tmp.pivot(r1);
447         if (indx == -1) {
448             return _ex0();
449         }
450         if (indx != 0) {
451             det *= _ex_1();
452         }
453         det = det * tmp.m[r1*M.cols()+r1];
454         for (unsigned r2=r1+1; r2<M.rows(); ++r2) {
455             piv = tmp.m[r2*M.cols()+r1] / tmp.m[r1*M.cols()+r1];
456             for (unsigned c=r1+1; c<M.cols(); c++) {
457                 tmp.m[r2*M.cols()+c] -= piv * tmp.m[r1*M.cols()+c];
458             }
459         }
460     }
461     return det;
462 }
463
464 // Compute the sign of a permutation of a vector of things, used internally
465 // by determinant_symbolic_perm() where it is instantiated for int.
466 template <class T>
467 int permutation_sign(vector<T> s)
468 {
469     if (s.size() < 2)
470         return 0;
471     int sigma=1;
472     for (typename vector<T>::iterator i=s.begin(); i!=s.end()-1; ++i) {
473         for (typename vector<T>::iterator j=i+1; j!=s.end(); ++j) {
474             if (*i == *j)
475                 return 0;
476             if (*i > *j) {
477                 iter_swap(i,j);
478                 sigma = -sigma;
479             }
480         }
481     }
482     return sigma;
483 }
484
485 /** Determinant built by application of the full permutation group. This
486  *  routine is only called internally by matrix::determinant(). */
487 ex determinant_symbolic_perm(const matrix & M)
488 {
489     GINAC_ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
490     
491     if (M.rows()==1) {  // speed things up
492         return M(0,0);
493     }
494     
495     ex det;
496     ex term;
497     vector<unsigned> sigma(M.cols());
498     for (unsigned i=0; i<M.cols(); ++i) sigma[i]=i;
499     
500     do {
501         term = M(sigma[0],0);
502         for (unsigned i=1; i<M.cols(); ++i) term *= M(sigma[i],i);
503         det += permutation_sign(sigma)*term;
504     } while (next_permutation(sigma.begin(), sigma.end()));
505     
506     return det;
507 }
508
509 /** Recursive determiant for small matrices having at least one symbolic entry.
510  *  This algorithm is also known as Laplace-expansion. This routine is only
511  *  called internally by matrix::determinant(). */
512 ex determinant_symbolic_minor(const matrix & M)
513 {
514     GINAC_ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
515     
516     if (M.rows()==1) {  // end of recursion
517         return M(0,0);
518     }
519     if (M.rows()==2) {  // speed things up
520         return (M(0,0)*M(1,1)-
521                 M(1,0)*M(0,1));
522     }
523     if (M.rows()==3) {  // speed things up even a little more
524         return ((M(2,1)*M(0,2)-M(2,2)*M(0,1))*M(1,0)+
525                 (M(1,2)*M(0,1)-M(1,1)*M(0,2))*M(2,0)+
526                 (M(2,2)*M(1,1)-M(2,1)*M(1,2))*M(0,0));
527     }
528     
529     ex det;
530     matrix minorM(M.rows()-1,M.cols()-1);
531     for (unsigned r1=0; r1<M.rows(); ++r1) {
532         // assemble the minor matrix
533         for (unsigned r=0; r<minorM.rows(); ++r) {
534             for (unsigned c=0; c<minorM.cols(); ++c) {
535                 if (r<r1) {
536                     minorM.set(r,c,M(r,c+1));
537                 } else {
538                     minorM.set(r,c,M(r+1,c+1));
539                 }
540             }
541         }
542         // recurse down
543         if (r1%2) {
544             det -= M(r1,0) * determinant_symbolic_minor(minorM);
545         } else {
546             det += M(r1,0) * determinant_symbolic_minor(minorM);
547         }
548     }
549     return det;
550 }
551
552 /*  Leverrier algorithm for large matrices having at least one symbolic entry.
553  *  This routine is only called internally by matrix::determinant(). The
554  *  algorithm is deemed bad for symbolic matrices since it returns expressions
555  *  that are very hard to canonicalize. */
556 /*ex determinant_symbolic_leverrier(const matrix & M)
557  *{
558  *    GINAC_ASSERT(M.rows()==M.cols());  // cannot happen, just in case...
559  *    
560  *    matrix B(M);
561  *    matrix I(M.row, M.col);
562  *    ex c=B.trace();
563  *    for (unsigned i=1; i<M.row; ++i) {
564  *        for (unsigned j=0; j<M.row; ++j)
565  *            I.m[j*M.col+j] = c;
566  *        B = M.mul(B.sub(I));
567  *        c = B.trace()/ex(i+1);
568  *    }
569  *    if (M.row%2) {
570  *        return c;
571  *    } else {
572  *        return -c;
573  *    }
574  *}*/
575
576 /** Determinant of square matrix.  This routine doesn't actually calculate the
577  *  determinant, it only implements some heuristics about which algorithm to
578  *  call.  When the parameter for normalization is explicitly turned off this
579  *  method does not normalize its result at the end, which might imply that
580  *  the symbolic 2x2 matrix [[a/(a-b),1],[b/(a-b),1]] is not immediatly
581  *  recognized to be unity.  (This is Mathematica's default behaviour, it
582  *  should be used with care.)
583  *
584  *  @param     normalized may be set to false if no normalization of the
585  *             result is desired (i.e. to force Mathematica behavior, Maple
586  *             does normalize the result).
587  *  @return    the determinant as a new expression
588  *  @exception logic_error (matrix not square) */
589 ex matrix::determinant(bool normalized) const
590 {
591     if (row != col) {
592         throw (std::logic_error("matrix::determinant(): matrix not square"));
593     }
594
595     // check, if there are non-numeric entries in the matrix:
596     for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) {
597         if (!(*r).info(info_flags::numeric)) {
598             if (normalized) {
599                 return determinant_symbolic_minor(*this).normal();
600             } else {
601                 return determinant_symbolic_perm(*this);
602             }
603         }
604     }
605     // if it turns out that all elements are numeric
606     return determinant_numeric(*this);
607 }
608
609 /** Trace of a matrix.
610  *
611  *  @return    the sum of diagonal elements
612  *  @exception logic_error (matrix not square) */
613 ex matrix::trace(void) const
614 {
615     if (row != col) {
616         throw (std::logic_error("matrix::trace(): matrix not square"));
617     }
618     
619     ex tr;
620     for (unsigned r=0; r<col; ++r) {
621         tr += m[r*col+r];
622     }
623     return tr;
624 }
625
626 /** Characteristic Polynomial.  The characteristic polynomial of a matrix M is
627  *  defined as the determiant of (M - lambda * 1) where 1 stands for the unit
628  *  matrix of the same dimension as M.  This method returns the characteristic
629  *  polynomial as a new expression.
630  *
631  *  @return    characteristic polynomial as new expression
632  *  @exception logic_error (matrix not square)
633  *  @see       matrix::determinant() */
634 ex matrix::charpoly(const ex & lambda) const
635 {
636     if (row != col) {
637         throw (std::logic_error("matrix::charpoly(): matrix not square"));
638     }
639     
640     matrix M(*this);
641     for (unsigned r=0; r<col; ++r) {
642         M.m[r*col+r] -= lambda;
643     }
644     return (M.determinant());
645 }
646
647 /** Inverse of this matrix.
648  *
649  *  @return    the inverted matrix
650  *  @exception logic_error (matrix not square)
651  *  @exception runtime_error (singular matrix) */
652 matrix matrix::inverse(void) const
653 {
654     if (row != col) {
655         throw (std::logic_error("matrix::inverse(): matrix not square"));
656     }
657     
658     matrix tmp(row,col);
659     // set tmp to the unit matrix
660     for (unsigned i=0; i<col; ++i) {
661         tmp.m[i*col+i] = _ex1();
662     }
663     // create a copy of this matrix
664     matrix cpy(*this);
665     for (unsigned r1=0; r1<row; ++r1) {
666         int indx = cpy.pivot(r1);
667         if (indx == -1) {
668             throw (std::runtime_error("matrix::inverse(): singular matrix"));
669         }
670         if (indx != 0) {  // swap rows r and indx of matrix tmp
671             for (unsigned i=0; i<col; ++i) {
672                 tmp.m[r1*col+i].swap(tmp.m[indx*col+i]);
673             }
674         }
675         ex a1 = cpy.m[r1*col+r1];
676         for (unsigned c=0; c<col; ++c) {
677             cpy.m[r1*col+c] /= a1;
678             tmp.m[r1*col+c] /= a1;
679         }
680         for (unsigned r2=0; r2<row; ++r2) {
681             if (r2 != r1) {
682                 ex a2 = cpy.m[r2*col+r1];
683                 for (unsigned c=0; c<col; ++c) {
684                     cpy.m[r2*col+c] -= a2 * cpy.m[r1*col+c];
685                     tmp.m[r2*col+c] -= a2 * tmp.m[r1*col+c];
686                 }
687             }
688         }
689     }
690     return tmp;
691 }
692
693 void matrix::ffe_swap(unsigned r1, unsigned c1, unsigned r2 ,unsigned c2)
694 {
695     ensure_if_modifiable();
696     
697     ex tmp=ffe_get(r1,c1);
698     ffe_set(r1,c1,ffe_get(r2,c2));
699     ffe_set(r2,c2,tmp);
700 }
701
702 void matrix::ffe_set(unsigned r, unsigned c, ex e)
703 {
704     set(r-1,c-1,e);
705 }
706
707 ex matrix::ffe_get(unsigned r, unsigned c) const
708 {
709     return operator()(r-1,c-1);
710 }
711
712 /** Solve a set of equations for an m x n matrix by fraction-free Gaussian
713  *  elimination. Based on algorithm 9.1 from 'Algorithms for Computer Algebra'
714  *  by Keith O. Geddes et al.
715  *
716  *  @param vars n x p matrix
717  *  @param rhs m x p matrix
718  *  @exception logic_error (incompatible matrices)
719  *  @exception runtime_error (singular matrix) */
720 matrix matrix::fraction_free_elim(const matrix & vars,
721                                   const matrix & rhs) const
722 {
723     if ((row != rhs.row) || (col != vars.row) || (rhs.col != vars.col)) {
724         throw (std::logic_error("matrix::solve(): incompatible matrices"));
725     }
726     
727     matrix a(*this); // make a copy of the matrix
728     matrix b(rhs);     // make a copy of the rhs vector
729     
730     // given an m x n matrix a, reduce it to upper echelon form
731     unsigned m=a.row;
732     unsigned n=a.col;
733     int sign=1;
734     ex divisor=1;
735     unsigned r=1;
736     
737     // eliminate below row r, with pivot in column k
738     for (unsigned k=1; (k<=n)&&(r<=m); ++k) {
739         // find a nonzero pivot
740         unsigned p;
741         for (p=r; (p<=m)&&(a.ffe_get(p,k).is_equal(_ex0())); ++p) {}
742         // pivot is in row p
743         if (p<=m) {
744             if (p!=r) {
745                 // switch rows p and r
746                 for (unsigned j=k; j<=n; ++j) {
747                     a.ffe_swap(p,j,r,j);
748                 }
749                 b.ffe_swap(p,1,r,1);
750                 // keep track of sign changes due to row exchange
751                 sign=-sign;
752             }
753             for (unsigned i=r+1; i<=m; ++i) {
754                 for (unsigned j=k+1; j<=n; ++j) {
755                     a.ffe_set(i,j,(a.ffe_get(r,k)*a.ffe_get(i,j)
756                                   -a.ffe_get(r,j)*a.ffe_get(i,k))/divisor);
757                     a.ffe_set(i,j,a.ffe_get(i,j).normal() /*.normal() */ );
758                 }
759                 b.ffe_set(i,1,(a.ffe_get(r,k)*b.ffe_get(i,1)
760                               -b.ffe_get(r,1)*a.ffe_get(i,k))/divisor);
761                 b.ffe_set(i,1,b.ffe_get(i,1).normal() /*.normal() */ );
762                 a.ffe_set(i,k,0);
763             }
764             divisor=a.ffe_get(r,k);
765             r++;
766         }
767     }
768     // optionally compute the determinant for square or augmented matrices
769     // if (r==m+1) { det=sign*divisor; } else { det=0; }
770     
771     /*
772     for (unsigned r=1; r<=m; ++r) {
773         for (unsigned c=1; c<=n; ++c) {
774             cout << a.ffe_get(r,c) << "\t";
775         }
776         cout << " | " <<  b.ffe_get(r,1) << endl;
777     }
778     */
779     
780 #ifdef DO_GINAC_ASSERT
781     // test if we really have an upper echelon matrix
782     int zero_in_last_row=-1;
783     for (unsigned r=1; r<=m; ++r) {
784         int zero_in_this_row=0;
785         for (unsigned c=1; c<=n; ++c) {
786             if (a.ffe_get(r,c).is_equal(_ex0())) {
787                zero_in_this_row++;
788             } else {
789                 break;
790             }
791         }
792         GINAC_ASSERT((zero_in_this_row>zero_in_last_row)||(zero_in_this_row=n));
793         zero_in_last_row=zero_in_this_row;
794     }
795 #endif // def DO_GINAC_ASSERT
796     
797     // assemble solution
798     matrix sol(n,1);
799     unsigned last_assigned_sol=n+1;
800     for (unsigned r=m; r>0; --r) {
801         unsigned first_non_zero=1;
802         while ((first_non_zero<=n)&&(a.ffe_get(r,first_non_zero).is_zero())) {
803             first_non_zero++;
804         }
805         if (first_non_zero>n) {
806             // row consists only of zeroes, corresponding rhs must be 0 as well
807             if (!b.ffe_get(r,1).is_zero()) {
808                 throw (std::runtime_error("matrix::fraction_free_elim(): singular matrix"));
809             }
810         } else {
811             // assign solutions for vars between first_non_zero+1 and
812             // last_assigned_sol-1: free parameters
813             for (unsigned c=first_non_zero+1; c<=last_assigned_sol-1; ++c) {
814                 sol.ffe_set(c,1,vars.ffe_get(c,1));
815             }
816             ex e=b.ffe_get(r,1);
817             for (unsigned c=first_non_zero+1; c<=n; ++c) {
818                 e=e-a.ffe_get(r,c)*sol.ffe_get(c,1);
819             }
820             sol.ffe_set(first_non_zero,1,
821                         (e/a.ffe_get(r,first_non_zero)).normal());
822             last_assigned_sol=first_non_zero;
823         }
824     }
825     // assign solutions for vars between 1 and
826     // last_assigned_sol-1: free parameters
827     for (unsigned c=1; c<=last_assigned_sol-1; ++c) {
828         sol.ffe_set(c,1,vars.ffe_get(c,1));
829     }
830
831     /*
832     for (unsigned c=1; c<=n; ++c) {
833         cout << vars.ffe_get(c,1) << "->" << sol.ffe_get(c,1) << endl;
834     }
835     */
836     
837 #ifdef DO_GINAC_ASSERT
838     // test solution with echelon matrix
839     for (unsigned r=1; r<=m; ++r) {
840         ex e=0;
841         for (unsigned c=1; c<=n; ++c) {
842             e=e+a.ffe_get(r,c)*sol.ffe_get(c,1);
843         }
844         if (!(e-b.ffe_get(r,1)).normal().is_zero()) {
845             cout << "e=" << e;
846             cout << "b.ffe_get(" << r<<",1)=" << b.ffe_get(r,1) << endl;
847             cout << "diff=" << (e-b.ffe_get(r,1)).normal() << endl;
848         }
849         GINAC_ASSERT((e-b.ffe_get(r,1)).normal().is_zero());
850     }
851
852     // test solution with original matrix
853     for (unsigned r=1; r<=m; ++r) {
854         ex e=0;
855         for (unsigned c=1; c<=n; ++c) {
856             e=e+ffe_get(r,c)*sol.ffe_get(c,1);
857         }
858         try {
859         if (!(e-rhs.ffe_get(r,1)).normal().is_zero()) {
860             cout << "e=" << e << endl;
861             e.printtree(cout);
862             ex en=e.normal();
863             cout << "e.normal()=" << en << endl;
864             en.printtree(cout);
865             cout << "rhs.ffe_get(" << r<<",1)=" << rhs.ffe_get(r,1) << endl;
866             cout << "diff=" << (e-rhs.ffe_get(r,1)).normal() << endl;
867         }
868         } catch (...) {
869             ex xxx=e-rhs.ffe_get(r,1);
870             cerr << "xxx=" << xxx << endl << endl;
871         }
872         GINAC_ASSERT((e-rhs.ffe_get(r,1)).normal().is_zero());
873     }
874 #endif // def DO_GINAC_ASSERT
875     
876     return sol;
877 }   
878     
879 /** Solve simultaneous set of equations. */
880 matrix matrix::solve(const matrix & v) const
881 {
882     if (!(row == col && col == v.row)) {
883         throw (std::logic_error("matrix::solve(): incompatible matrices"));
884     }
885     
886     // build the extended matrix of *this with v attached to the right
887     matrix tmp(row,col+v.col);
888     for (unsigned r=0; r<row; ++r) {
889         for (unsigned c=0; c<col; ++c) {
890             tmp.m[r*tmp.col+c] = m[r*col+c];
891         }
892         for (unsigned c=0; c<v.col; ++c) {
893             tmp.m[r*tmp.col+c+col] = v.m[r*v.col+c];
894         }
895     }
896     for (unsigned r1=0; r1<row; ++r1) {
897         int indx = tmp.pivot(r1);
898         if (indx == -1) {
899             throw (std::runtime_error("matrix::solve(): singular matrix"));
900         }
901         for (unsigned c=r1; c<tmp.col; ++c) {
902             tmp.m[r1*tmp.col+c] /= tmp.m[r1*tmp.col+r1];
903         }
904         for (unsigned r2=r1+1; r2<row; ++r2) {
905             for (unsigned c=r1; c<tmp.col; ++c) {
906                 tmp.m[r2*tmp.col+c]
907                     -= tmp.m[r2*tmp.col+r1] * tmp.m[r1*tmp.col+c];
908             }
909         }
910     }
911     
912     // assemble the solution matrix
913     exvector sol(v.row*v.col);
914     for (unsigned c=0; c<v.col; ++c) {
915         for (unsigned r=col-1; r>=0; --r) {
916             sol[r*v.col+c] = tmp[r*tmp.col+c];
917             for (unsigned i=r+1; i<col; ++i) {
918                 sol[r*v.col+c]
919                     -= tmp[r*tmp.col+i] * sol[i*v.col+c];
920             }
921         }
922     }
923     return matrix(v.row, v.col, sol);
924 }
925
926 // protected
927
928 /** Partial pivoting method.
929  *  Usual pivoting returns the index to the element with the largest absolute
930  *  value and swaps the current row with the one where the element was found.
931  *  Here it does the same with the first non-zero element. (This works fine,
932  *  but may be far from optimal for numerics.) */
933 int matrix::pivot(unsigned ro)
934 {
935     unsigned k=ro;
936     
937     for (unsigned r=ro; r<row; ++r) {
938         if (!m[r*col+ro].is_zero()) {
939             k = r;
940             break;
941         }
942     }
943     if (m[k*col+ro].is_zero()) {
944         return -1;
945     }
946     if (k!=ro) {  // swap rows
947         for (unsigned c=0; c<col; ++c) {
948             m[k*col+c].swap(m[ro*col+c]);
949         }
950         return k;
951     }
952     return 0;
953 }
954
955 //////////
956 // global constants
957 //////////
958
959 const matrix some_matrix;
960 const type_info & typeid_matrix=typeid(some_matrix);
961
962 #ifndef NO_NAMESPACE_GINAC
963 } // namespace GiNaC
964 #endif // ndef NO_NAMESPACE_GINAC