// // $Source: /cvsroot/gambit/gambit/sources/tools/lp/ludecomp.imp,v $ // $Date: 2006/01/07 06:37:34 $ // $Revision: 1.6 $ // // DESCRIPTION: // Implementation of LU decomposition // // This file is part of Gambit // Copyright (c) 2002, The Gambit Project // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include "ludecomp.h" #include "tableau.h" // --------------------------------------------------------------------------- // Class EtaMatrix // --------------------------------------------------------------------------- template bool EtaMatrix::operator==(const EtaMatrix &a) const { return ( col == a.col && etadata == a.etadata ); } template bool EtaMatrix::operator!=(const EtaMatrix &a) const { return ( col != a.col || etadata != a.etadata ); } // --------------------------------------------------------------------------- // Class LUdecomp // --------------------------------------------------------------------------- // ------------------------- // C-tors, D-tor, Operators // ------------------------- // copy constructor template LUdecomp::LUdecomp( const LUdecomp &a, Tableau &t) : tab(t), basis(t.GetBasis()), scratch1(basis.First(), basis.Last()), scratch2(basis.First(), basis.Last()), refactor_number( a.refactor_number ), iterations(a.iterations), total_operations( a.total_operations), parent(&a), copycount(0) { ((LUdecomp &)*parent).copycount++; } // Decomposes given matrix template LUdecomp::LUdecomp( Tableau &t, int rfac/* = 0 */) : tab(t), basis(t.GetBasis()), scratch1(basis.First(), basis.Last()), scratch2(basis.First(), basis.Last()), refactor_number(rfac), iterations(0), parent(NULL), copycount(0) { int m = basis.Last() - basis.First() +1; total_operations = (m - 1) * m * (2 * m - 1) / 6; } // Destructor template LUdecomp::~LUdecomp() { if ( parent != NULL ) ((LUdecomp &) *parent).copycount--; if(copycount != 0) throw BadCount(); } // ------------------------- // Public Members // ------------------------- // use this to copy ludecomps.... template void LUdecomp::Copy(const LUdecomp &orig, Tableau &t) { if(this != &orig) { if (parent != NULL) ((LUdecomp &) *parent).copycount--; tab = t; basis = t.GetBasis(); L = Gambit::List >(); P = Gambit::List(); E = Gambit::List >(); U = Gambit::List >(); refactor_number = orig.refactor_number; iterations = orig.iterations; total_operations = orig.total_operations; parent = &orig; copycount = 0; ((LUdecomp &)*parent).copycount++; } } template void LUdecomp::update( int col, int matcol ) { if( copycount != 0 ) throw BadCount(); int m = basis.Last() - basis.First() + 1; iterations++; if (( refactor_number > 0 && iterations >= refactor_number ) || ( refactor_number == 0 && RefactorCheck()) ) refactor(); else { tab.GetColumn( matcol, scratch1); solve( scratch1, scratch1 ); if ( scratch1[col] == (T) 0 ) throw BadPivot(); E.Append( EtaMatrix( col, scratch1 ) ); total_operations += iterations * m + 2 * m * m; } } template void LUdecomp::refactor( ) { L = Gambit::List >(); U = Gambit::List >(); E = Gambit::List >(); P = Gambit::List(); if ( !basis.IsIdent() ) FactorBasis(); iterations = 0; int m = basis.Last() - basis.First() + 1; total_operations = (m - 1) * m * (2 * m - 1) / 6; if (parent != NULL) ((LUdecomp &)*parent).copycount--; parent = NULL; } template void LUdecomp::solveT( const Gambit::Vector &c, Gambit::Vector &y ) const { if ( c.First() != y.First() || c.Last() != y.Last() ) throw Gambit::DimensionException(); if ( c.First() != basis.First() || c.Last() != basis.Last()) throw Gambit::DimensionException(); y = c; if ( basis.IsIdent() != true ) { BTransE( y ); if ( parent != NULL ) (*parent).solveT( y, y ); else { FTransU( y ); yLP_Trans( y ); } } } template void LUdecomp::solve( const Gambit::Vector &a, Gambit::Vector &d ) const { if ( a.First() != d.First() || a.Last() != d.Last() ) throw Gambit::DimensionException(); if ( a.First() != basis.First() || a.Last() != basis.Last()) throw Gambit::DimensionException(); d = a; if ( basis.IsIdent() != true ) { if ( parent != NULL ) (*parent).solve(a,d); else { LPd_Trans( d ); BTransU( d ); } FTransE( d ); } } template void LUdecomp::SetRefactor( int a ) { refactor_number = a; } // ----------------- // Private Members // ----------------- template void LUdecomp::FactorBasis() { int i, j, piv; T pivVal; Gambit::Matrix B(basis.First(), basis.Last(), basis.First(), basis.Last()); for( i = basis.First(); i <= basis.Last(); i++ ) { tab.GetColumn( basis.Label(i), scratch2 ); basis.CheckBasis(); B.SetColumn( i, scratch2 ); } for ( i = B.MinRow(); i <= B.MaxRow(); i++) { pivVal = Gambit::abs ( B(i, i)); piv = i; for ( j = i+1; j <= B.MaxRow(); j++) { if ( B( j, i ) * B( j, i ) > pivVal * pivVal ) { piv = j; pivVal = B( j, i ); } } P.Append(piv); B.SwitchRows(i,piv); scratch2 = (T) 0; scratch2[i] = (T) 1 / B( i, i ); for ( j = i+1; j <= B.MaxRow(); j++ ) { scratch2[j] = - B(j, i) / B(i,i); } L.Append( EtaMatrix(i, scratch2) ); GaussElem(B, i, i); } for ( j = B.MinCol(); j <= B.MaxCol(); j++ ) { B.GetColumn( j, scratch2 ); U.Append( EtaMatrix( j, scratch2 )); } } template void LUdecomp::GaussElem(Gambit::Matrix &B, int row, int col) { if( B(row, col) == (T) 0) throw BadPivot(); int i,j; for ( j = col+1; j <= B.MaxCol(); j++) B( row, j ) = B( row, j ) / B( row, col ); for ( i = row+1; i <= B.MaxRow(); i++ ) for ( j = col+1; j <= B.MaxCol(); j++ ) { B( i, j ) = B( i, j ) - ( B( i, col ) * B( row, j ) ); } for ( i = row+1; i <= B.MaxRow(); i++ ) B( i , col ) = 0; B( row, col ) = (T) 1; } template void LUdecomp::BTransE( Gambit::Vector &y ) const { int i; for ( i = E.Length(); i >= 1; i-- ) { ((LUdecomp &) *this).scratch2 = y; VectorEtaSolve(scratch2, E[i], y ); } } template void LUdecomp::FTransU( Gambit::Vector &y ) const { int i; for ( i = 1; i <= U.Length(); i++ ) { ((LUdecomp &) *this).scratch2 = y; VectorEtaSolve(scratch2, U[i], y ); } } template void LUdecomp::VectorEtaSolve( const Gambit::Vector &v, const EtaMatrix &eta, Gambit::Vector &y ) const { int i, j; if ( v.First() != y.First() || v.Last() != y.Last() ) throw Gambit::DimensionException(); for ( i = v.First(); i <= v.Last(); i++ ) { y[i] = v[i]; if ( i == eta.col ) { for ( j = v.First(); j <= v.Last(); j++ ) if ( j != eta.col ) y[i] -= v[j] * eta.etadata[j]; y[i] /= eta.etadata[i]; } } } template void LUdecomp::FTransE( Gambit::Vector &y ) const { int i; for ( i = 1; i <= E.Length(); i++ ) { ((LUdecomp &) *this).scratch2 = y; EtaVectorSolve(scratch2, E[i], y ); } } template void LUdecomp::BTransU( Gambit::Vector &y ) const { int i; for ( i = U.Length(); i >= 1; i-- ) { ((LUdecomp &) *this).scratch2 = y; EtaVectorSolve(scratch2, U[i], y ); } } template void LUdecomp::EtaVectorSolve( const Gambit::Vector &v, const EtaMatrix &eta, Gambit::Vector &d ) const { int i; T temp; if ( v.First() != d.First() || v.Last() != d.Last() ) throw Gambit::DimensionException(); if ( eta.etadata[eta.col] == (T)0 ) throw BadPivot(); // or we would have a singular matrix temp = v[eta.col] / eta.etadata[eta.col]; for ( i = v.First(); i <= v.Last(); i++) { if ( i == eta.col ) d[i] = temp; else { d[i] = v[i] - temp * eta.etadata[i]; } } } template void LUdecomp::yLP_Trans( Gambit::Vector &y ) const { int j; for (j = L.Length(); j >= 1; j--) { yLP_mult( y, j, ((LUdecomp &) *this).scratch2 ); y = scratch2; } } template void LUdecomp::yLP_mult( const Gambit::Vector &y, int j, Gambit::Vector &ans ) const { if ( ans.First() != y.First() || ans.Last() != y.Last() ) throw Gambit::DimensionException(); T temp; int i, k, l; l = j + y.First() - 1; for (i = y.First(); i <= y.Last(); i++) { if ( i != L[j].col) ans[i] = y[i]; else { for ( k = ans.First(), temp = (T) 0; k <= ans.Last(); k++) { temp += y[k] * L[j].etadata[k]; } ans[i] = temp; } } temp = ans[l]; ans[l] = ans[P[j]]; ans[P[j]] = temp; } template void LUdecomp::LPd_Trans( Gambit::Vector &d ) const { int j; for (j = 1; j <= L.Length(); j++) { LPd_mult( d, j, ((LUdecomp &) *this).scratch2 ); d = scratch2; } } template void LUdecomp::LPd_mult( Gambit::Vector &d, int j, Gambit::Vector &ans ) const { if ( d.First() != ans.First() || d.Last() != ans.Last() ) throw Gambit::DimensionException(); T temp; int i, k; k = j + d.First() - 1; temp = d[k]; d[k] = d[P[j]]; d[P[j]] = temp; for (i = d.First(); i <= d.Last(); i++) { if ( i == L[j].col ) ans[i] = d[i] * L[j].etadata[i]; else { ans[i] = d[i] + d[ L[j].col ] * L[j].etadata[i]; } } d[P[j]] = d[k]; d[k] = temp; } template bool LUdecomp::CheckBasis() { int i; bool ret = true; for (i = basis.First(); i <= basis.Last() && ret != false; i++) ret = ret && ( basis.Label(i) == -i ); return ret; } template bool LUdecomp::RefactorCheck() { int m = basis.Last() - basis.First() + 1; int i = iterations * (iterations * m + 2 * m * m ); int k = total_operations + iterations * m + 2 * m * m; bool tmp; tmp = ( i > k ); return tmp; } template LUdecomp::BadCount::~BadCount() { } template std::string LUdecomp::BadCount::GetDescription(void) const { return "Bad Reference count in LUdecomp"; } template LUdecomp::BadPivot::~BadPivot() { } template std::string LUdecomp::BadPivot::GetDescription(void) const { return "Bad Pivot in LUdecomp"; }