@@ -384,6 +384,9 @@ template <class T> Vector<T> Matrix<T>::Column(int j) const
384384
385385template <class T> void Matrix<T>::MakeIdent()
386386{
387+ if (!IsSquare()) {
388+ throw DimensionException();
389+ }
387390 for (int i = this->minrow; i <= this->maxrow; i++) {
388391 for (int j = this->mincol; j <= this->maxcol; j++) {
389392 if (i == j) {
@@ -426,4 +429,139 @@ template <class T> void Matrix<T>::Pivot(int row, int col)
426429 }
427430}
428431
432+ template <class T> Matrix<T> Matrix<T>::Inverse() const
433+ {
434+ if (!IsSquare()) {
435+ throw DimensionException();
436+ }
437+
438+ Matrix copy(*this);
439+ Matrix inv(this->MaxRow(), this->MaxRow());
440+
441+ // initialize inverse matrix and prescale row vectors
442+ for (int i = this->MinRow(); i <= this->MaxRow(); i++) {
443+ T max = (T)0;
444+ for (int j = this->MinCol(); j <= this->MaxCol(); j++) {
445+ T abs = copy(i, j);
446+ if (abs < (T)0) {
447+ abs = -abs;
448+ }
449+ if (abs > max) {
450+ max = abs;
451+ }
452+ }
453+
454+ if (max == (T)0) {
455+ throw SingularMatrixException();
456+ }
457+
458+ T scale = (T)1 / max;
459+ for (int j = this->MinCol(); j <= this->MaxCol(); j++) {
460+ copy(i, j) *= scale;
461+ if (i == j) {
462+ inv(i, j) = scale;
463+ }
464+ else {
465+ inv(i, j) = (T)0;
466+ }
467+ }
468+ }
469+
470+ for (int i = this->MinCol(); i <= this->MaxCol(); i++) {
471+ // find pivot row
472+ T max = copy(i, i);
473+ if (max < (T)0) {
474+ max = -max;
475+ }
476+ int row = i;
477+ for (int j = i + 1; j <= this->MaxRow(); j++) {
478+ T abs = copy(j, i);
479+ if (abs < (T)0) {
480+ abs = -abs;
481+ }
482+ if (abs > max) {
483+ max = abs;
484+ row = j;
485+ }
486+ }
487+
488+ if (max <= (T)0) {
489+ throw SingularMatrixException();
490+ }
491+
492+ copy.SwitchRows(i, row);
493+ inv.SwitchRows(i, row);
494+ // scale pivot row
495+ T factor = (T)1 / copy(i, i);
496+ for (int k = this->MinCol(); k <= this->MaxCol(); k++) {
497+ copy(i, k) *= factor;
498+ inv(i, k) *= factor;
499+ }
500+
501+ // reduce other rows
502+ for (int j = this->MinRow(); j <= this->MaxRow(); j++) {
503+ if (j != i) {
504+ T mult = copy(j, i);
505+ for (int k = this->MinCol(); k <= this->MaxCol(); k++) {
506+ copy(j, k) -= copy(i, k) * mult;
507+ inv(j, k) -= inv(i, k) * mult;
508+ }
509+ }
510+ }
511+ }
512+
513+ return inv;
514+ }
515+
516+ template <class T> T Matrix<T>::Determinant() const
517+ {
518+ if (!IsSquare()) {
519+ throw DimensionException();
520+ }
521+
522+ T factor = (T)1;
523+ Matrix M(*this);
524+
525+ for (int row = this->MinRow(); row <= this->MaxRow(); row++) {
526+
527+ // Experience (as of 3/22/99) suggests that, in the interest of
528+ // numerical stability, it might be best to do Gaussian
529+ // elimination with respect to the row (of those feasible)
530+ // whose entry has the largest absolute value.
531+ int swap_row = row;
532+ for (int i = row + 1; i <= this->MaxRow(); i++) {
533+ if (abs(M.data[i][row]) > abs(M.data[swap_row][row])) {
534+ swap_row = i;
535+ }
536+ }
537+
538+ if (swap_row != row) {
539+ M.SwitchRows(row, swap_row);
540+ for (int j = this->MinCol(); j <= this->MaxCol(); j++) {
541+ M.data[row][j] *= (T)-1;
542+ }
543+ }
544+
545+ if (M.data[row][row] == (T)0) {
546+ return (T)0;
547+ }
548+
549+ // now do row operations to clear the row'th column
550+ // below the diagonal
551+ for (int row1 = row + 1; row1 <= this->MaxRow(); row1++) {
552+ factor = -M.data[row1][row] / M.data[row][row];
553+ for (int i = this->MinCol(); i <= this->MaxCol(); i++) {
554+ M.data[row1][i] += M.data[row][i] * factor;
555+ }
556+ }
557+ }
558+
559+ // finally we multiply the diagonal elements
560+ T det = (T)1;
561+ for (int row = this->MinRow(); row <= this->MaxRow(); row++) {
562+ det *= M.data[row][row];
563+ }
564+ return det;
565+ }
566+
429567} // end namespace Gambit
0 commit comments