Modelib: Fichier source de Model.cpp

Page principale | Liste des namespaces | Hiérarchie des classes | Liste alphabétique | Liste des classes | Liste des fichiers | Membres de namespace | Membres de classe | Membres de fichier

# Model.cpp

Aller à la documentation de ce fichier.

    00001 /*
    00002     Copyright (c) 2005, Quentin Lequy and Romain Gaucher
    00003     All rights reserved.
    00004
    00005     Redistribution and use in source and binary forms, with or
    00006     without modification, are permitted provided that the following
    00007     conditions are met:
    00008
    00009         * Redistributions of source code must retain the above copyright
    00010           notice, this list of conditions and the following disclaimer.
    00011
    00012         * Redistributions in binary form must reproduce the above copyright
    00013           notice, this list of conditions and the following disclaimer in the
    00014           documentation and/or other materials provided with the distribution.
    00015
    00016         * Neither the name of Quentin Lequy or Romain Gaucher nor the names
    00017           of its contributors may be used to endorse or promote products
    00018           derived from this software without specific prior written permission.
    00019
    00020     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    00021     AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    00022     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    00023     ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    00024     LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    00025     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    00026     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    00027     AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00028     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00029     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00030 */
    00031
    00032 #include "Model.h"
    00033 #include "FichierLP.h"
    00034 #include "FichierMPS.h"
    00035 #include <list>
    00036 #include <iostream>
    00037 #include <sstream>
    00038 #include <cmath>
    00039 #include <stdexcept>
    00040
    00041 namespace Modelib {
    00042
    00043 using namespace std;
    00044
    00046 Model::Model(const Model &m)
    00047 {
    00048     *this = m;
    00049 }
    00050
    00052 Model & Model::operator=(const Model &m)
    00053 {
    00054     if( this != &m)
    00055     {
    00056       hacheVarId=m.hacheVarId;
    00057       unknowMap=m.unknowMap;
    00058       A.matrix = m.A.matrix;
    00059       A.nbLignes = m.A.nbLignes;
    00060       A.nbCols = m.A.nbCols;
    00061       constraintMap = m.constraintMap;
    00062
    00063       isMax = m.isMax;
    00064       isRelaxed = m.isRelaxed;
    00065       isFract = m.isFract;
    00066       isOptimal = m.isOptimal;
    00067       isSolved = m.isSolved;
    00068       MIPVar = m.MIPVar;
    00069
    00070       objectif = m.objectif;
    00071       objectifActivity = m.objectifActivity;
    00072       objectifName = m.objectifName;
    00073       problemName = m.problemName;
    00074
    00075       solverAPI = m.solverAPI;
    00076     }
    00077     return *this;
    00078 }
    00079
    00080 /*-------------------------------------------------------------------------------------------------------*/
    00084 float Model::GetLagrangianParamValue( VarId id ) const
    00085 {
    00086   std::map<VarId,InternalConstraint>::const_iterator trouve = constraintMap.find(id);
    00087   if(trouve!=constraintMap.end())
    00088      return trouve->second.lagrangianValue;
    00089   else
    00090      cerr << "Warning in Model::GetLagrangianParamValue : undefined id " << id<< endl;
    00091   return 0;
    00092 }
    00093
    00094
    00098 void Model::SetLagrangianParamValue(VarId id, float value)
    00099 {
    00100   std::map<VarId,InternalConstraint>::iterator trouve = constraintMap.find(id);
    00101   if( trouve!=constraintMap.end())
    00102   {
    00103     //selon le type de contrainte les domaines de définition du multiplicateur varient
    00104     switch(trouve->second.type)
    00105     {
    00106         case InternalConstraint::INFSTRICT :
    00107         case InternalConstraint::INF :
    00108         //Pour les contraintes de type inférieur, le multiplicateur est positif
    00109         if(value < 0)
    00110           {
    00111              value = 0;
    00112            cerr << "Warning in Model::SetLagrangianParamValue : constraint " << id
    00113                   << " lagrangian value is out of his definition area" << endl;
    00114           }
    00115         break;
    00116
    00117         case InternalConstraint::SUPSTRICT :
    00118         case InternalConstraint::SUP :
    00119         //Pour les contraintes de type inférieur, le multiplicateur est positif
    00120         if(value > 0)
    00121           {
    00122              value = 0;
    00123              cerr << "Warning in Model::SetLagrangianParamValue : constraint " << id
    00124                   << " lagrangian value is out of his definition area" << endl;
    00125           }
    00126         break;
    00127
    00128         case InternalConstraint::EGAL :
    00129         //Pour les contraintes de type egal, le multiplicateur est réel
    00130         break;
    00131
    00132         default:
    00133            cerr << "Warning in Model::SetLagrangianParamValue : wrong InternalConstraint::Type" << endl;
    00134         break;
    00135      }
    00136      trouve->second.lagrangianValue = value;
    00137   }
    00138   else
    00139      cerr << "Warning in Model::SetLagrangianParamValue : undefined id " << id << endl;
    00140 }
    00141
    00142
    00143 /*--------------------------------------------------------------------------------------------------------*/
    00151 VarId Model::AddVar( const MuteVar & muteVar, const std::string & _nom )
    00152 {
    00153   string tmpnom;
    00154   //futur nom de la variable
    00155   //si la variable n'a pas de nom défini
    00156   if( _nom == "unknow" )
    00157   {
    00158     char * nomId = new char[30];
    00159     //on recupere son futur identifiant dans un buffer de caractère
    00160     sprintf(nomId,"%d",hacheVarId);
    00161     tmpnom = _nom + nomId ;
    00162     //le futur nom de la variable sera donc unknow{id}
    00163     delete [] nomId;
    00164     //on libere le buffer
    00165   }
    00166   else
    00167     tmpnom = _nom;
    00168   //sinon on son futur nom est le nom donner par l'utilisateur
    00169   unknowMap[hacheVarId]=Paire(muteVar,tmpnom);
    00170   //on insere la variable dans le map
    00171   if( muteVar.GetType() != MuteVar::FLOAT)
    00172     MIPVar++;
    00173   //si la variable n'est pas continues on augmente le compteur des variables MIP
    00174   return hacheVarId++;
    00175   //on retourne l'identifiant puis on l'augmente
    00176 }
    00177
    00178 /*--------------------------------------------------------------------------------------------------------*/
    00184 MuteVar Model::GetMuteVar( VarId varId) const
    00185 {
    00186   std::map<VarId,Paire>::const_iterator trouve = unknowMap.find(varId);
    00187   if(trouve!=unknowMap.end())
    00188      return trouve->second.variable;
    00189   else
    00190      cerr << "Warning in Model::GetMuteVar : undefined id " << varId << endl;
    00191   return MuteVar();
    00192 }
    00193
    00194
    00200 NumVar Model::GetNumVar( VarId varId) const
    00201 {
    00202   return NumVar(this,varId);
    00203 }
    00204
    00210 std::string Model::GetName( VarId varId ) const
    00211 {
    00212   std::map<VarId,Paire>::const_iterator trouve = unknowMap.find(varId);
    00213   if(trouve!=unknowMap.end())
    00214      return trouve->second.nom;
    00215   else
    00216      cerr << "Warning in Model::GetName : undefined id " << varId << endl;
    00217   return defaultGetName;
    00218 }
    00219
    00225 void Model::SetName( VarId varId, const std::string & name )
    00226 {
    00227   std::map<VarId,Paire>::iterator trouve = unknowMap.find(varId);
    00228   if(trouve!=unknowMap.end())
    00229      trouve->second.nom = name;
    00230   else
    00231      cerr << "Warning in Model::GetName : undefined id " << varId << endl;
    00232 }
    00233
    00234 VarId Model::GetVarId(const std::string & name) const
    00235 {
    00236    std::map<VarId,Paire>::const_iterator trouve = unknowMap.begin();
    00237    VarId retour = 0;
    00238    //Pour toutes les variables
    00239    for(;trouve!=unknowMap.end();++trouve)
    00240      //si on trouve le nom
    00241      if(trouve->second.nom == name)
    00242      {
    00243        retour = trouve->first;
    00244        //on récupère l'identifiant et on arrête la boucle
    00245        break;
    00246      }
    00247    if(retour == 0)
    00248      cerr << "Warning in Model::GetVarId : undefined name " << name << endl;
    00249    return retour;
    00250
    00251 }
    00252
    00253
    00254 /*--------------------------------------------------------------------------------------------------------*/
    00260 float Model::GetMuteVarLB( VarId varId) const
    00261 {
    00262   std::map<VarId,Paire>::const_iterator trouve = unknowMap.find(varId);
    00263   if(trouve!=unknowMap.end())
    00264      return (trouve->second.variable).GetLowerBound();
    00265   else
    00266      cerr << "Warning in Model::GetMuteVarLB : undefined id " << varId << endl;
    00267   return 0.0;
    00268 }
    00269
    00275 void Model::SetMuteVarLB( VarId varId, float _value)
    00276 {
    00277   std::map<VarId,Paire>::iterator trouve = unknowMap.find(varId);
    00278   if(trouve!=unknowMap.end())
    00279      (trouve->second.variable).SetLowerBound( _value);
    00280   else
    00281       cerr << "Warning in Model::SetMuteVarLB : undefined id " << varId << endl;
    00282  return;
    00283 }
    00284
    00285 /*--------------------------------------------------------------------------------------------------------*/
    00291 float Model::GetMuteVarUB( VarId varId) const
    00292 {
    00293   std::map<VarId,Paire>::const_iterator trouve = unknowMap.find(varId);
    00294   if(trouve!=unknowMap.end())
    00295      return  (trouve->second.variable).GetUpperBound();
    00296   else
    00297       cerr << "Warning in Model::GetMuteVarUB : undefined id " << varId << endl;
    00298   return Infinity;
    00299 }
    00300
    00301
    00307 void Model::SetMuteVarUB( VarId varId, float _value)
    00308 {
    00309   std::map<VarId,Paire>::iterator trouve = unknowMap.find(varId);
    00310   if(trouve!=unknowMap.end())
    00311      (trouve->second.variable).SetUpperBound( _value);
    00312   else
    00313       cerr << "Warning in Model::SetMuteVarUB : undefined id " << varId << endl;
    00314   return;
    00315 }
    00316
    00317 /*--------------------------------------------------------------------------------------------------------*/
    00324 void Model::SetMuteVarLBStrict( VarId varId, bool _value)
    00325 {
    00326   std::map<VarId,Paire>::iterator trouve = unknowMap.find(varId);
    00327   if(trouve!=unknowMap.end())
    00328      (trouve->second.variable).SetIsLBStrict( _value);
    00329   else
    00330       cerr << "Warning in Model::SetMuteVarLBStrict : undefined id " << varId << endl;
    00331   return;
    00332 }
    00333
    00340 void Model::SetMuteVarUBStrict( VarId varId, bool _value)
    00341 {
    00342   std::map<VarId,Paire>::iterator trouve = unknowMap.find(varId);
    00343   if(trouve!=unknowMap.end())
    00344      (trouve->second.variable).SetIsUBStrict( _value);
    00345   else
    00346       cerr << "Warning in Model::SetMuteVarUBStrict : undefined id " << varId << endl;
    00347   return;
    00348 }
    00349
    00350 /*--------------------------------------------------------------------------------------------------------*/
    00356 MuteVar::VarType Model::GetType( VarId varId) const
    00357 {
    00358   std::map<VarId,Paire>::const_iterator trouve = unknowMap.find(varId);
    00359   if(trouve!=unknowMap.end())
    00360      return (trouve->second.variable).GetType();
    00361   else
    00362      cerr << "Warning in Model::GetType : undefined id " << varId << endl;
    00363   return MuteVar::FLOAT;
    00364 }
    00365
    00371 void Model::SetType(  VarId varId, MuteVar::VarType _type)
    00372 {
    00373   std::map<VarId,Paire>::iterator trouve = unknowMap.find(varId);
    00374   if(trouve!=unknowMap.end())
    00375   {
    00376     if( trouve->second.variable.GetType()!=MuteVar::FLOAT
    00377       &&  _type == MuteVar::FLOAT)
    00378          MIPVar++;
    00379     if( trouve->second.variable.GetType()==MuteVar::FLOAT
    00380        &&  _type != MuteVar::FLOAT)
    00381          MIPVar--;
    00382     (trouve->second.variable).SetType( _type);
    00383   }
    00384   else
    00385      cerr << "Warning in Model::SetType : undefined id " << varId << endl;
    00386   return;
    00387 }
    00388
    00389 /*--------------------------------------------------------------------------------------------------------*/
    00394 void Model::Maximize(const Expr & expr , const std::string & name )
    00395 {
    00396    objectif = expr;
    00397    objectif.Simplify();
    00398    isMax = true;
    00399    objectifName = name;
    00400 }
    00401
    00406 void Model::Minimize(const Expr & expr, const std::string & name )
    00407 {
    00408    objectif = expr;
    00409    objectif.Simplify();
    00410    isMax = false;
    00411    objectifName = name;
    00412 }
    00413
    00414 /*--------------------------------------------------------------------------------------------------------*/
    00422 VarId Model::AddExpr( Expr & expr , MatriceCreuse<float> & A )
    00423 {
    00424    std::list<ExprNode>::iterator iter;
    00425    unsigned p = A.GetNbLignes()+1;
    00426    for( iter = expr.nodeList.begin(); iter != expr.nodeList.end(); ++iter)
    00427    {
    00428       float coef = iter->GetCoefficient().GetValue();
    00429       NumVar varTmp = iter->GetVariable();
    00430       VarId varId = (varTmp.GetModel()?varTmp.GetVarId():0);
    00431       if(varId && unknowMap.find(varId) != unknowMap.end())
    00432       {
    00433         A.Set(varId,p,coef);
    00434       }
    00435       else
    00436       {
    00437         if(varId)
    00438             cerr << "Warning in Model::AddExpr : undefined id " << varId << endl;
    00439       }
    00440     }
    00441   return hacheConstraintId++;
    00442 }
    00443
    00444 /*---------------------------------------------------------------------------------------*/
    00445
    00452 //Attention: Contraint a mettre ici
    00453 Constraint Model::Add( const ConstraintBuilder & c , const std::string & nom)
    00454 {
    00455   Constraint retour;
    00456   if( c.IsBound() )  //La contrainte est une borne
    00457   {
    00458        NumVar var = (++c.expressions.begin())->nodeList.front().GetVariable();
    00459
    00460        //La borne est de type: {value} {Operateur} {Variable} ou {Variable} {Operateur} {value}
    00461        if(c.operateurs.size()==1)
    00462        {
    00463
    00464          float bound;
    00465          bool prems = ( c.expressions.back().nodeList.front().GetVariable().GetModel() == 0 );
    00466          //booleen servant a savoir si la variable est en premier ou pas
    00467          //si elle est en premier
    00468          if(prems)
    00469             bound = c.expressions.back().nodeList.front().GetCoefficient().GetValue();
    00470             //on récupere le coefficient de la seconde partie de l'expression qui est la borne supérieure
    00471          else
    00472             bound = c.expressions.front().nodeList.front().GetCoefficient().GetValue();
    00473             //on récupere le coefficient de la premire partie de l'expression qui est la borne inférieure
    00474          list<ConstraintBuilder::Operateur>::const_iterator op = c.operateurs.begin();
    00475          //En cas de contraintes stricte il faut modifié le caractere des borne
    00476          //suivant le type de contraintes
    00477          switch( *op )
    00478          {
    00479            case ConstraintBuilder::INFSTRICT: //cas similaire à INFERIEUR
    00480               if(prems)
    00481                  var.SetUpperBoundStrict( true );
    00482               else
    00483                  var.SetLowerBoundStrict( true );
    00484            case ConstraintBuilder::INFERIEUR:
    00485               if(prems)
    00486                  var.SetUpperBound( bound );
    00487               else
    00488                  var.SetLowerBound( bound );
    00489            break;
    00490            case ConstraintBuilder::SUPSTRICT: //cas similaire à SUPERIEUR
    00491               if(!prems)
    00492                  var.SetUpperBoundStrict( true );
    00493               else
    00494                  var.SetLowerBoundStrict( true );
    00495            case ConstraintBuilder::SUPERIEUR:
    00496              if(!prems)
    00497                  var.SetUpperBound( bound );
    00498               else
    00499                  var.SetLowerBound( bound );
    00500            break;
    00501            default:
    00502                  cerr << "Warning in Model::Add : wrong ConstraintBuilder::Operator for single constraint" << endl;
    00503            break;
    00504          }
    00505        }
    00506
    00507        //La Contrainte est de la forme {value} {Operateur} {variable} {Operateur} {value}
    00508        if(c.operateurs.size()==2)
    00509        {
    00510          float lrB = c.expressions.front().nodeList.front().GetCoefficient().GetValue();
    00511          //on récupere la borne inférieure
    00512          float urB = c.expressions.back().nodeList.front().GetCoefficient().GetValue();
    00513          //on récupere la borne supérieure
    00514          list<ConstraintBuilder::Operateur>::const_iterator op = c.operateurs.begin();
    00515          //on récupere l'opérateur de comparaison
    00516          float swap;
    00517          //En cas de contraintes superieure il faut inverser les bornes
    00518          switch( *op )
    00519          {
    00520            case ConstraintBuilder::INFSTRICT:
    00521              var.SetLowerBoundStrict( true );
    00522            break;
    00523            case ConstraintBuilder::INFERIEUR:
    00524            break;
    00525            case ConstraintBuilder::SUPSTRICT:
    00526              var.SetUpperBoundStrict( true );
    00527            case ConstraintBuilder::SUPERIEUR:
    00528              swap = lrB;
    00529              lrB = urB;
    00530              urB = swap;
    00531            break;
    00532            default:
    00533              cerr << "Warning in Model::Add : wrong ConstraintBuilder::Operator for double constraint" << endl;
    00534            break;
    00535          }
    00536          ++op;
    00537          //on récupere l'opérateur de comparaison suivant
    00538          if( *op == ConstraintBuilder::INFSTRICT)
    00539            var.SetUpperBoundStrict( true );
    00540          if( *op == ConstraintBuilder::SUPSTRICT)
    00541            var.SetLowerBoundStrict( true );
    00542          var.SetLowerBound( lrB );
    00543          var.SetUpperBound( urB );
    00544        }
    00545   }
    00546   //sinon c'est une contrainte generique
    00547   else
    00548   {
    00549     if( c.operateurs.size() >=1 && c.operateurs.size() + 1 == c.expressions.size()  )
    00550     {
    00551         //La contrainte est valide
    00552       list<Expr>::const_iterator exp = c.expressions.begin();
    00553         list<Expr>::const_iterator exp2 = ++c.expressions.begin();
    00554         list<ConstraintBuilder::Operateur>::const_iterator op = c.operateurs.begin();
    00555
    00556         //Decompostion de la suite de contraintes
    00557         while( exp2!=c.expressions.end() )
    00558         {
    00559           Expr tmp; //expressions temporaire qui va aider à séparer la chaine de contraintes
    00560           ostringstream id;
    00561           if(c.operateurs.size()!=1 || nom.length()== 0 )
    00562              if( nom.length()== 0 )
    00563                 id << "__c" << A.nbLignes+1;
    00564              else
    00565                 id << nom << A.nbLignes+1;
    00566           else
    00567               id << nom;
    00568           string nom2 = id.str();
    00569
    00570           tmp = *exp - *exp2;
    00571           //la partie linéaire de la contrainte est le premier membre moins le second membre
    00572           tmp.Simplify();
    00573           //on simplifie
    00574
    00575           VarId p;
    00576           float coef = -(tmp.nodeList.front().GetVariable().GetModel()?0.0f:tmp.nodeList.front().GetCoefficient().GetValue());
    00577           //on recupere le coefficient qui se trouve en premiere position dans l'expression
    00578           //suivant le type de contrainte
    00579           //on ajoute la partie linéaire à la matrice
    00580           //et on créé la representation interne de la contrainte dans le vecteur de contrainte
    00581           switch( *op )
    00582           {
    00583             case ConstraintBuilder::INFERIEUR:
    00584                p = AddExpr( tmp, A );
    00585                constraintMap[p] = InternalConstraint(InternalConstraint::INF,coef,0.0,0.0,nom2,false,false);
    00586             break;
    00587
    00588             case ConstraintBuilder::SUPERIEUR:
    00589                p = AddExpr( tmp, A );
    00590                constraintMap[p] = InternalConstraint(InternalConstraint::SUP,coef,0.0,0.0,nom2,false,false);
    00591             break;
    00592
    00593             case ConstraintBuilder::EGAL:
    00594                p = AddExpr( tmp, A );
    00595                constraintMap[p] = InternalConstraint(InternalConstraint::EGAL,coef,0.0,0.0,nom2,false,false);
    00596             break;
    00597
    00598             case ConstraintBuilder::INFSTRICT:
    00599                p = AddExpr( tmp, A );
    00600                constraintMap[p] = InternalConstraint(InternalConstraint::INFSTRICT,coef,0.0,0.0,nom2,false,false);
    00601             break;
    00602
    00603             case ConstraintBuilder::SUPSTRICT:
    00604                p = AddExpr( tmp, A );
    00605                constraintMap[p] = InternalConstraint(InternalConstraint::SUPSTRICT,coef,0.0,0.0,nom2,false,false);
    00606             break;
    00607
    00608             default:
    00609               cerr << "Warning in Model::Add : wrong ConstraintBuilder::Operator" << endl;
    00610               break;
    00611           }
    00612            ++exp2;++exp;++op;
    00613            //on passe à  la contrainte suivante
    00614            retour = Constraint(*this,p);
    00615         }
    00616     }
    00617     else
    00618       cerr << "Warning in Model::Add : the ConstraintBuilder is bad structured" << endl;
    00619   }
    00620   return retour;
    00621 }
    00622
    00623
    00624 /*---------------------------------------------------------------------------------------*/
    00625
    00631 std::ostream & Model::Out( std::ostream & flux, const std::string & newline )
    00632 {
    00633     flux << (isMax?"Maximize: ":"Minimize") << objectif << newline << endl << endl;
    00634     flux << "A =" << newline << endl;
    00635     A.Out();
    00636     flux << "Matrice de taille: " << A.GetNbLignes()
    00637         << "x" << A.GetNbCols() << newline << endl;
    00638     return flux;
    00639 }
    00640
    00641
    00642 /*---------------------------------------------------------------------------------------*/
    00643
    00650 std::ostream& Model::SurchargeFlux(std::ostream& flux) const
    00651 {
    00652     flux << "\\" << problemName << endl;
    00653
    00654     if( isMax)
    00655         flux <<  "Maximize " << endl;
    00656     else
    00657         flux <<  "Minimize " << endl;
    00658     flux << objectifName << (objectifName.length()?": ":" ") << objectif << endl;
    00659
    00660     flux << endl << "Subject to" << endl;
    00661
    00662     string op[]  = { "<=",">=","="," > "," < "};
    00663
    00664
    00665     VarId p = A.nbLignes+1;
    00666     bool normal = false;
    00667
    00668     std::map<VarId,Paire>::const_iterator variable;
    00669     std::map<VarId,InternalConstraint>::const_iterator constraint = constraintMap.end();
    00670     std::map<VarId,std::string>::const_iterator comment = comments.begin();
    00671
    00672     for(map< Id,float,Compare<float> >::const_iterator iter  = A.matrix.begin();
    00673                                                        iter != A.matrix.end();
    00674                                                      ++iter)
    00675     {
    00676         unsigned i = iter->first.i; //colonne
    00677         unsigned j = iter->first.j; //ligne attention au décalage d'indice avec tB
    00678
    00679         variable  = unknowMap.find(VarId(i));
    00680
    00681         if(j != p)  //nouvelle contrainte
    00682         {
    00683             if(constraint != constraintMap.end())
    00684                 flux << op[constraint->second.type] << constraint->second.b << endl;
    00685
    00686             constraint = constraintMap.find(j);
    00687             p = constraint->first;
    00688
    00689             while( comment != comments.end() && comment->first <= p)
    00690             {
    00691                 flux << "\\" << comment->second << endl;
    00692                 ++comment;
    00693             }
    00694             if( constraint->second.name.length())
    00695                 flux << constraint->second.name << ": ";
    00696
    00697             normal = false;
    00698         }
    00699
    00700         float coeff = iter->second;
    00701
    00702         if( normal )
    00703         {
    00704             if(coeff != 0.0f)
    00705             {
    00706                 if(coeff != 1.0f && coeff != -1.0f )
    00707                         if( coeff > 0 )
    00708                                flux  << "+" << coeff << variable->second.nom;
    00709                         else
    00710                                flux << coeff << variable->second.nom;
    00711                 else
    00712                         if( coeff == 1.0f )
    00713                                flux  << "+" << variable->second.nom;
    00714                         else
    00715                                flux  << "-" << variable->second.nom;
    00716             }
    00717         }
    00718         else
    00719         {
    00720             if(coeff != 0.0f)
    00721             {
    00722                 if(coeff != 1.0f && coeff != -1.0f )
    00723                     flux  << coeff << variable->second.nom;
    00724                 else
    00725                     flux << (coeff == 1.0?"":"-") << variable->second.nom;
    00726                 normal = true;
    00727             }
    00728         }
    00729
    00730     }
    00731     if(constraint != constraintMap.end())
    00732         flux << op[constraint->second.type] << constraint->second.b << endl;
    00733
    00734     while( comment != comments.end() )
    00735     {
    00736         flux << "\\" << comment->second << endl;
    00737         ++comment;
    00738     }
    00739
    00740
    00741     bool bounds = false;
    00742     for(std::map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    00743                                               variable != unknowMap.end();
    00744                                             ++variable)
    00745     {
    00746         bool lbs = variable->second.variable.IsLowerBoundStrict();
    00747         bool ubs = variable->second.variable.IsUpperBoundStrict();
    00748         float lb = variable->second.variable.GetLowerBound();
    00749         float ub = variable->second.variable.GetUpperBound();
    00750
    00751         if( variable->second.variable.GetType() != MuteVar::BOOL)
    00752         {
    00753             if( (lb != 0 || ub != Infinity) && bounds == false  )
    00754             {
    00755                flux << endl << "Bounds" << endl;
    00756                  bounds = true;
    00757               }
    00758             if( bounds == true )
    00759             {
    00760                 if(lb == -Infinity && ub == Infinity)
    00761                     flux <<  variable->second.nom << " Free";
    00762                 else
    00763                 {
    00764                    if(lb!=0.0)
    00765                    {
    00766                        if( lb != -Infinity )
    00767                             flux << lb << (lbs?" < ":"<=");
    00768                         else
    00769                             flux << "-Inf" << " < ";
    00770                     }
    00771
    00772                     if(ub!=Infinity)
    00773                         flux << variable->second.nom << (ubs?" < ":" <= ") << ub;
    00774                     else
    00775                         if(lb!=0.0)
    00776                             flux << variable->second.nom;
    00777                 }
    00778                 if( lb!=0.0 || ub!=Infinity )
    00779                   flux << endl;
    00780             }
    00781         }
    00782     }
    00783
    00784     bool generals = false;
    00785     for(std::map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    00786                                             variable != unknowMap.end();
    00787                                           ++variable)
    00788     {
    00789         if(variable->second.variable.GetType() == MuteVar::INT)
    00790         {
    00791             if(generals)
    00792                 flux << variable->second.nom << endl;
    00793             else
    00794             {
    00795                 flux << endl  << "Generals" << endl
    00796                      << variable->second.nom << endl;
    00797                 generals = true;
    00798             }
    00799         }
    00800     }
    00801
    00802
    00803     bool binaries = false;
    00804     for(std::map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    00805                                             variable != unknowMap.end();
    00806                                           ++variable)
    00807     {
    00808         if(variable->second.variable.GetType() == MuteVar::BOOL)
    00809         {
    00810             if(binaries == true)
    00811                 flux << variable->second.nom << endl;
    00812             else
    00813             {
    00814                 flux << endl << endl << "Binaries" << endl
    00815                      << variable->second.nom << endl;
    00816                 binaries = true;
    00817             }
    00818         }
    00819     }
    00820
    00821     flux<< endl << endl << "End" << endl;
    00822
    00823     return flux;
    00824 }
    00825
    00829 std::ostream & Model::OutDimensions( std::ostream & flux, const std::string & newline)
    00830 {
    00831    flux << "Tailles des matrices:" << newline << endl;
    00832    flux << "   Matrice des inégalités: " << A.GetNbLignes()
    00833         << "x" << A.GetNbCols() << newline << endl
    00834         << "       taux d'occupation: "
    00835         << (A.GetNbLignes()!=0.0f?A.matrix.size()*100.0/(1.0*A.nbLignes*A.nbCols):0)
    00836         << "% "   << endl << newline;
    00837    flux << "Nombre de Variables:  " << unknowMap.size() << newline << endl;
    00838    flux << "Nombre de Contraintes:  " << constraintMap.size() << newline << endl;
    00839    flux << "Taille de la fonction objectif:  " << objectif.Size() << newline << endl;
    00840    return flux;
    00841 }
    00842
    00843 /*---------------------------------------------------------------------------------------*/
    00844
    00850 std::ostream& Model::SurchargeFluxRelaxed(std::ostream& flux) const
    00851 {
    00852
    00853   flux << "\\" << problemName << endl;
    00854
    00855 /*  list<ExprNode>::const_iterator src = objectif.nodeList.begin();
    00856
    00857   for(;src!=objectif.nodeList.end();++src)
    00858     cout << "+" << src->GetCoefficient() << "*" << src->GetVariable().GetName()
    00859          << "*" << src->GetLagrangianParam().GetValue();
    00860     cout << endl;
    00861 */
    00862     if( isMax)
    00863         flux <<  "Maximize " << endl;
    00864     else
    00865         flux <<  "Minimize " << endl;
    00866     flux << "\\Constante à ajouter: " << objectif.GetConstant( true ) << endl;
    00867     flux << objectifName << (objectifName.length()?": ":" ") << objectif << endl;
    00868
    00869     flux << endl << "Subject to" << endl;
    00870
    00871     string op[]  = { "<=",">=","="," > "," < "};
    00872
    00873     VarId p = A.nbLignes+1;
    00874     bool normal = false;
    00875
    00876     map<VarId,Paire>::const_iterator variable;
    00877     map<VarId,InternalConstraint>::const_iterator constraint = constraintMap.end();
    00878     map<VarId,std::string>::const_iterator comment = comments.begin();
    00879
    00880     for(map< Id,float,Compare<float> >::const_iterator iter  = A.matrix.begin();
    00881                                                        iter != A.matrix.end();
    00882                                                      ++iter)
    00883     {
    00884         unsigned i = iter->first.i; //colonne
    00885         unsigned j = iter->first.j; //ligne
    00886
    00887         variable  = unknowMap.find(VarId(i));
    00888
    00889         if(j != p)  //nouvelle contrainte
    00890         {
    00891              if(  constraint != constraintMap.end()
    00892              && !constraint->second.isLagrangianParamActive )
    00893                 flux << op[constraint->second.type] << constraint->second.b << endl;
    00894
    00895             constraint = constraintMap.find(j);
    00896             p = constraint->first;
    00897
    00898             while( comment != comments.end() && comment->first <= p)
    00899             {
    00900                 flux << "\\" << comment->second << endl;
    00901                 ++comment;
    00902             }
    00903
    00904             if( constraint->second.name.length() && !constraint->second.isLagrangianParamActive)
    00905                 flux << constraint->second.name << ": ";
    00906
    00907             normal = false;
    00908         }
    00909
    00910         float coeff = iter->second;
    00911
    00912         if( !constraint->second.isLagrangianParamActive )
    00913         {
    00914             if( normal )
    00915             {
    00916                 if(coeff != 0.0f)
    00917                 {
    00918                     if(coeff != 1.0f && coeff != -1.0f )
    00919                             if( coeff > 0 )
    00920                                    flux  << "+" << coeff << variable->second.nom;
    00921                             else
    00922                                    flux << coeff << variable->second.nom;
    00923                     else
    00924                             if( coeff == 1.0f )
    00925                                    flux  << "+" << variable->second.nom;
    00926                             else
    00927                                    flux  << "-" << variable->second.nom;
    00928                 }
    00929             }
    00930             else
    00931             {
    00932                 if(coeff != 0.0f)
    00933                 {
    00934                     if(coeff != 1.0f && coeff != -1.0f )
    00935                         flux  << coeff << variable->second.nom;
    00936                     else
    00937                         flux << (coeff == 1.0?"":"-") << variable->second.nom;
    00938                     normal = true;
    00939                 }
    00940             }
    00941         }
    00942
    00943     }
    00944     if(  constraint != constraintMap.end()
    00945      && !constraint->second.isLagrangianParamActive )
    00946         flux << op[constraint->second.type] << constraint->second.b << endl;
    00947
    00948     while( comment != comments.end() )
    00949     {
    00950         flux << "\\" << comment->second << endl;
    00951         ++comment;
    00952     }
    00953
    00954
    00955   bool bounds = false;
    00956   for(map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    00957                                        variable != unknowMap.end();
    00958                                      ++variable)
    00959   {
    00960     bool lbs = variable->second.variable.IsLowerBoundStrict();
    00961     bool ubs = variable->second.variable.IsUpperBoundStrict();
    00962     float lb = variable->second.variable.GetLowerBound();
    00963     float ub = variable->second.variable.GetUpperBound();
    00964
    00965     if( variable->second.variable.GetType() != MuteVar::BOOL)
    00966     {
    00967       if( (lb != 0 || ub != Infinity) && bounds == false )
    00968       {
    00969         flux << endl << "Bounds" << endl;
    00970         bounds = true;
    00971       }
    00972
    00973       if( bounds == true )
    00974       {
    00975         if(lb == -Infinity && ub == Infinity)
    00976             flux <<  variable->second.nom << " Free";
    00977         else
    00978         {
    00979             if(lb!=0.0)
    00980             {
    00981                if( lb != -Infinity )
    00982                  flux << lb << (lbs?" < ":"<=");
    00983                else
    00984                  flux << "-Inf" << " < ";
    00985             }
    00986
    00987             if(ub!=Infinity)
    00988                flux << variable->second.nom << (ubs?" < ":"<=") << ub;
    00989             else
    00990                if(lb!=0.0)
    00991                  flux << variable->second.nom;
    00992         }
    00993         if( lb!=0.0 || ub!=Infinity )
    00994           flux << endl;
    00995       }
    00996     }
    00997   }
    00998
    00999   bool generals = false;
    01000   for(map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    01001                                        variable != unknowMap.end();
    01002                                      ++variable)
    01003   {
    01004      if(variable->second.variable.GetType() == MuteVar::INT && !variable->second.variable.IsRelaxed())
    01005      {
    01006         if( generals == true )
    01007           flux << variable->second.nom << endl;
    01008         else
    01009         {
    01010             flux << endl  << "Generals" << endl
    01011                  << variable->second.nom << endl;
    01012             generals = true;
    01013         }
    01014      }
    01015   }
    01016
    01017
    01018   bool binaries = false;
    01019   for(map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    01020                                        variable != unknowMap.end();
    01021                                      ++variable)
    01022   {
    01023      if(variable->second.variable.GetType() == MuteVar::BOOL && !variable->second.variable.IsRelaxed())
    01024      {
    01025         if(binaries == true )
    01026           flux << variable->second.nom << endl;
    01027         else
    01028         {
    01029             flux << endl << endl << "Binaries" << endl
    01030                  << variable->second.nom << endl;
    01031             binaries = true;
    01032         }
    01033      }
    01034   }
    01035
    01036   flux<< endl << endl << "End" << endl;
    01037
    01038   return flux;
    01039 }
    01040
    01046 std::ostream& operator<<(std::ostream& flux,const Model& m)
    01047 {
    01048   if( m.IsRelaxed() )
    01049      return m.SurchargeFluxRelaxed(flux);
    01050   else
    01051      return m.SurchargeFlux(flux);
    01052
    01053 }
    01054
    01055
    01056 /*-----------------------------------------------------------------------------------------------*/
    01057
    01063 std::ostream & Model::SurchargeMPSFlux(std::ostream & flux,bool verbose) const
    01064 {
    01065   string pbName(problemName,0,8);
    01066   if( problemName.length() >= 8 )
    01067   {
    01068     cerr << "Warning in Model::SurchargeMPSFlux : the probleme name is too long for MPS" << endl;
    01069   }
    01070   string::size_type endline = pbName.find('\n');
    01071   if( endline != string::npos && verbose==true )
    01072   {
    01073     cerr << "Warning in Model::SurchargeMPSFlux : the probleme name is reduced to a single line" << endl;
    01074   }
    01075   pbName = pbName.substr(0,endline);
    01076   flux << "NAME          " << pbName << endl;
    01077
    01078   string objName(objectifName,0,8);
    01079   if( objectifName.length() > 8 && verbose==true )
    01080   {
    01081     cerr << "Warning in Model::SurchargeMPSFlux : the objectif name is too long for MPS format" << endl;
    01082   }
    01083
    01084   flux << "ROWS" << endl << " N  " << objName << endl;
    01085   map<VarId, InternalConstraint>::const_iterator constraint;
    01086   string strType[5] = {" L  "," G  "," E  "," L  "," G  "};
    01087   for( constraint = constraintMap.begin(); constraint != constraintMap.end(); ++constraint )
    01088   {
    01089     string strConstraintName(constraint->second.name);
    01090     if( strConstraintName.length() > 8 )
    01091     {
    01092       if( verbose==true )
    01093         cerr << "Warning in Model::SurchargeMPSFlux : The constraint " << strConstraintName << " has a too long name for the MPS format. This name will be replaced by ";
    01094       strConstraintName = Nom("_",constraint->first)();
    01095       if( verbose==true )
    01096         cerr << strConstraintName << "." << endl;
    01097    }
    01098      flux << strType[int(constraint->second.type)] << strConstraintName << endl;
    01099   }
    01100
    01101   map< VarId, ostringstream * > tempM;
    01102   map< VarId, ostringstream *>::iterator iterStr;
    01103   list< ostringstream * > generals[2];
    01104   list< ostringstream * >::iterator iterlistStr;
    01105   for(map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    01106                                        variable != unknowMap.end();
    01107                                      ++variable)
    01108   {
    01109     ostringstream * nom = new ostringstream;
    01110     string variableName( variable->second.nom);
    01111     if( variableName.length() > 8 )
    01112     {
    01113       if( verbose==true )
    01114         cerr << "Warning in Model::SurchargeMPSFlux : The variable " << variableName << " has a too long name for the MPS format. This name will be replaced by ";
    01115       variableName = Nom("_",variable->first)();
    01116       if( verbose==true )
    01117         cerr << variableName << "." << endl;
    01118     }
    01119     *nom << variableName;
    01120     tempM[variable->first] = nom;
    01121     unsigned i = (variable->second.variable.GetType() == MuteVar::INT?0:1);
    01122     generals[i].push_back(nom);
    01123   }
    01124
    01125    std::list<ExprNode>::const_iterator iter;
    01126    float signe = (isMax?-1.0:1.0);
    01127
    01128    for( iter = objectif.nodeList.begin(); iter != objectif.nodeList.end(); ++iter)
    01129    {
    01130       NumVar varTmp = iter->GetVariable();
    01131       VarId varId = (varTmp.GetModel()?varTmp.GetVarId():0);
    01132
    01133       iterStr = tempM.find(varId);
    01134       if( iterStr != tempM.end() )
    01135       {
    01136          float coef = iter->GetCoefficient().GetValue();
    01137          *(iterStr->second)  << " " << objName << " " << signe*coef;
    01138       }
    01139    }
    01140
    01141   VarId p = A.nbLignes+1;
    01142   string strConstraintName;
    01143   for(map< Id,float,Compare<float> >::const_iterator iter  = A.matrix.begin();
    01144                                                      iter != A.matrix.end();
    01145                                                    ++iter)
    01146   {
    01147       unsigned i = iter->first.i; //colonne
    01148       unsigned j = iter->first.j; //ligne
    01149
    01150       if(j != p)  //nouvelle contrainte
    01151       {
    01152           constraint = constraintMap.find(j);
    01153           p = constraint->first;
    01154
    01155           strConstraintName = constraint->second.name;
    01156           if( strConstraintName.length() > 8 )
    01157           {
    01158             strConstraintName = Nom("_",j)();
    01159           }
    01160       }
    01161
    01162       float coeff = iter->second;
    01163
    01164       iterStr = tempM.find((VarId)i);
    01165       if( iterStr != tempM.end() )
    01166       {
    01167          *(iterStr->second)  << " " << strConstraintName << " " << coeff;
    01168       }
    01169   }
    01170
    01171   flux << "COLUMNS" << endl;
    01172   string markers[2];
    01173   if( generals[0].size() != 0 )
    01174   {
    01175     markers[0] = "    MARK0000  'MARKER'                 'INTORG'";
    01176     markers[1] = "    MARK0000  'MARKER'                 'INTEND'";
    01177   }
    01178   else
    01179   {
    01180     markers[0] = "";
    01181     markers[1] = "";
    01182   }
    01183
    01184
    01185   for( unsigned i=0; i < 2; ++ i)
    01186   {
    01187     flux << markers[i] << endl;
    01188     for( iterlistStr = generals[i].begin(); iterlistStr != generals[i].end();  ++iterlistStr )
    01189     {
    01190       istringstream chaine((*iterlistStr)->str());
    01191       string variable;
    01192       string row;
    01193       string value;
    01194       string row2;
    01195       string value2;
    01196
    01197       chaine >> variable;
    01198
    01199       variable+=string(8-variable.length(),' ') ;
    01200
    01201       while( chaine >> row >> value )
    01202       {
    01203         if( !(chaine >> row2 >> value2) )
    01204         {
    01205           row2="";
    01206           value2="";
    01207         }
    01208         row+=string(8-row.length(),' ') ;
    01209         value+=string(14-value.length(),' ') ;
    01210         row2+=string(8-row2.length(),' ') ;
    01211         value2+=string(14-value2.length(),' ') ;
    01212         flux << "    " << variable
    01213              << "  " << row
    01214              << "  " << value
    01215              << "  " << row2
    01216              << "  " << value2
    01217              << endl;
    01218       }
    01219       delete *iterlistStr;
    01220     }
    01221   }
    01222
    01223   flux << "RHS" << endl;
    01224   for( constraint = constraintMap.begin(); constraint != constraintMap.end(); ++constraint )
    01225   {
    01226     string strConstraintName(constraint->second.name);
    01227     if( strConstraintName.length() > 8 )
    01228     {
    01229       strConstraintName = Nom("_",constraint->first)();
    01230     }
    01231     strConstraintName+=string(8-strConstraintName.length(),' ');
    01232     flux << "    rhs       " << strConstraintName << "  " << constraint->second.b << endl;
    01233   }
    01234
    01235   flux << "BOUNDS" << endl;
    01236   for(map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    01237                                        variable != unknowMap.end();
    01238                                      ++variable)
    01239   {
    01240     float lb = variable->second.variable.GetLowerBound();
    01241     float ub = variable->second.variable.GetUpperBound();
    01242     string variableName( variable->second.nom);
    01243     if( variableName.length() > 8 )
    01244     {
    01245       variableName = Nom("_",variable->first)();
    01246     }
    01247     variableName+=string(8-variableName.length(),' ');
    01248
    01249     if( variable->second.variable.GetType() == MuteVar::BOOL )
    01250     {
    01251           flux << " BV bnd       " << variableName  << endl;
    01252     }
    01253     else
    01254     {
    01255         if( lb != -Infinity || ub != Infinity )
    01256       {
    01257         if( lb != -Infinity  )
    01258         {
    01259           if( !(lb == 0 && ub == Infinity) )
    01260           {
    01261             flux << " LO bnd       " << variableName << "  " << lb << endl;
    01262           }
    01263         }
    01264         else
    01265         {
    01266           flux << " MI bnd       " << variableName << endl;
    01267         }
    01268         if( ub != Infinity )
    01269         {
    01270           flux << " UP bnd       " << variableName << "  " << ub << endl;
    01271         }
    01272       }
    01273       else
    01274       {
    01275           flux << " FR bnd       " << variableName  << endl;
    01276       }
    01277     }
    01278   }
    01279   flux << "ENDATA" << endl;
    01280
    01281   return flux;
    01282 }
    01283
    01289 std::ostream & ToMPS(std::ostream& flux, const Model& m, bool verbose)
    01290 {
    01291   return m.SurchargeMPSFlux(flux,verbose);
    01292 }
    01293
    01294 /*-----------------------------------------------------------------------------------------------*/
    01299 Constraint Model::GetConstraint(VarId id) const
    01300 {
    01301     map<VarId,InternalConstraint>::const_iterator constraint;
    01302     constraint = constraintMap.find(id);
    01303     //on cherche la contraint
    01304     if(constraint != constraintMap.end())
    01305     {
    01306         return Constraint(*this,id);
    01307     }
    01308     else
    01309         cerr << "Warning in Model::GetConstraint : undefined id " << id << endl;
    01310     return Constraint();
    01311 }
    01312
    01318 bool Model::RelaxConstraint( VarId id, float lagrangianValue )
    01319 {
    01320     map<VarId,InternalConstraint>::iterator constraint;
    01321     //on va chercher la contrainte d'identifiant id
    01322     constraint = constraintMap.find(id);
    01323     //si on la trouve
    01324     if(constraint != constraintMap.end())
    01325     {
    01326         isRelaxed = true;
    01327         //on indique au modele qu'il est relaxee
    01328         constraint->second.lagrangianValue = lagrangianValue;
    01329         //on attribue la valeur du lagrangien
    01330         //si elle n'est pas -infini
    01331         if(lagrangianValue != -Infinity)
    01332            constraint->second.isLagrangianParamDefined = true ;
    01333            //le multiplicateur de lagrange est defini
    01334         constraint->second.isLagrangianParamActive = true;
    01335         //le multiplicateur de lagrange devient actif
    01336         objectif-=GetRelaxedConstraintExpr(id);
    01337         //on modifie la fonction objectif
    01338         objectif.isParametric = true;
    01339         //on lui indique qu'elle depend maintenant d'un multiplicateur de lagrange
    01340         objectif.sansConstantes = true;
    01341         //on lui indique de ne pas tenir compte des constantes qu'elle contient
    01342         return true;
    01343     }
    01344     else
    01345        cerr << "Warning in Model::RelaxConstraint: undefined constraint id " << id << endl;
    01346     return false;
    01347 }
    01348
    01355 float Model::EvalConstraint(VarId id ) const
    01356 {
    01357   float ret = 0.0f;
    01358
    01359   unsigned p = id;
    01360   std::map< Id,float,Compare<float> >::const_iterator iter  = A.matrix.begin();
    01361   while(iter != A.matrix.end())
    01362   {
    01363      unsigned i = iter->first.i; //indice de colonne
    01364      unsigned j = iter->first.j; //indice de ligne
    01365
    01366      //si on est sur la ligne de la contrainte
    01367      if(j == p)
    01368      {
    01369          ret += iter->second*GetMuteVar(i).GetValue();
    01370          //on ajoute le produit du coefficient et de la valeur
    01371          //de la variable au reel de retour
    01372      }
    01373      else
    01374      if(j>p)
    01375        break;
    01376        //si on depasse la contrainte on quitte
    01377
    01378      ++iter;
    01379   }
    01380   return ret;
    01381 }
    01382
    01388 Expr Model::GetRelaxedConstraintExpr( VarId id , bool relaxed)
    01389 {
    01390
    01391   Expr ret;
    01392   //expression de retour
    01393
    01394   LagrangianParam mult(*this, id);
    01395
    01396   if(!relaxed)
    01397     mult = LagrangianParam();
    01398
    01399   //multiplicateur de lagrange
    01400   std::map< Id,float,Compare<float> >::const_iterator iter  = A.matrix.begin();
    01401   //on parcourt la matrice creuse
    01402   while(iter != A.matrix.end())
    01403   {
    01404      unsigned i = iter->first.i; //indice de colonne
    01405      unsigned j = iter->first.j; //indice de ligne
    01406
    01407      //si on est sur la bonne ligne
    01408      if(j == id)
    01409      {
    01410          ret.ASS( iter->second, NumVar(this,i), mult);
    01411          //on ajoute le produit du coefficient et de la variable à l'expression
    01412      }
    01413      else
    01414      if(j>id)
    01415        break;
    01416        //si on depasse la ligne de la contrainte on quitte la boucle
    01417      ++iter;
    01418   }
    01419   float b = 0;
    01420   if( ret.Size() != 0)
    01421      b = constraintMap.find(id)->second.b;
    01422   ret.ASS( - b,NumVar(),mult);
    01423   ret.isParametric = true;
    01424   return ret;
    01425 }
    01426
    01434 bool Model::Relax(const std::string & name, float lagrangianValue )
    01435 {
    01436    VarId id;
    01437    //si on arrive a recuperer l'identifiant de la contrainte
    01438    if((id=GetConstraintId(name)))
    01439      return RelaxConstraint(id,lagrangianValue);
    01440      //on la relaxe
    01441    else
    01442      return false;
    01443 }
    01444
    01445
    01446 /*-----------------------------------------------------------------------------------------------*/
    01454 bool Model::RelaxInt2Float( NumVar numVar )
    01455 {
    01456   VarId id = numVar.GetVarId();
    01457   //on recupere l'identifiant de la variable
    01458
    01459   //si l'identifiant n'est pas nul
    01460   if(id)
    01461      unknowMap.find(id)->second.variable.SetRelaxed();
    01462      //on relaxe la variable correspondante
    01463   else
    01464     //sinon pour chaque variables
    01465     for(map<VarId,Paire>::iterator variable  = unknowMap.begin();
    01466                                         variable != unknowMap.end();
    01467                                       ++variable)
    01468     {
    01469         //on regarde si elle est de type entier
    01470         if(variable->second.variable.GetType()==MuteVar::INT)
    01471         {
    01472             variable->second.variable.SetRelaxed();
    01473             //si oui on la relaxe
    01474         }
    01475     }
    01476   return true;
    01477 }
    01478
    01486 bool Model::RelaxBool2Float( NumVar numVar )
    01487 {
    01488   VarId id = numVar.GetVarId();
    01489   //On recupere l'identifiant de la variable
    01490
    01491   //si l'identifiant n'est pas nul
    01492   if(id)
    01493      unknowMap.find(id)->second.variable.SetRelaxed();
    01494      //on relaxe la varaiable
    01495   else
    01496     //sinon pour chaque variable
    01497     for(map<VarId,Paire>::iterator variable  = unknowMap.begin();
    01498                                         variable != unknowMap.end();
    01499                                       ++variable)
    01500     {
    01501         //si elle est du type booleen
    01502         if(variable->second.variable.GetType()==MuteVar::BOOL)
    01503         {
    01504             variable->second.variable.SetRelaxed();
    01505             //on la relaxe
    01506         }
    01507     }
    01508   return true;
    01509 }
    01510
    01511
    01515 void Model::UnrelaxModel()
    01516 {
    01517    objectif.Simplify(false);
    01518    objectif.isParametric = false;
    01519    objectif.sansConstantes = false;
    01520    //on reinitialise la fonction objectif
    01521
    01522    //Pour toutes les variables
    01523    for(map<VarId,Paire>::iterator variable  = unknowMap.begin();
    01524                                   variable != unknowMap.end();
    01525                                 ++variable)
    01526         variable->second.variable.SetRelaxed(false);
    01527         //on leur enleve le caractere relachee
    01528
    01529    //pour toutes les contraintes
    01530    for(map<VarId,InternalConstraint>::iterator constraint  = constraintMap.begin();
    01531                                                constraint != constraintMap.end();
    01532                                              ++constraint)
    01533    {
    01534       constraint->second.isLagrangianParamActive = false;
    01535       //on desactive leur multiplicateur de lagrange
    01536    }
    01537    isRelaxed=false;
    01538 }
    01539
    01540
    01541 //-------------------------
    01542 // Interface des Solvers
    01543 //-------------------------
    01544
    01546 void  Model::SetAPI(API _API)
    01547 {
    01548     solverAPI.SetAPI(_API);
    01549 }
    01550
    01552 float Model::Solve()
    01553 {
    01554     float val;
    01555
    01556     ofstream out(solverAPI.GetfLP());
    01557     if(!out.is_open())
    01558        throw runtime_error("Model::Solve() : I/O Error");
    01559     //on declare un fichier .lp temporaire de sortie
    01560     out << (*this);
    01561     //on met le modele dans ce fichier sous la bonne forme
    01562     out.close();
    01563     //on ferme ce fichier pour eviter des problemes de lecture
    01564
    01565     solverAPI.SetMIP( MIPVar == 0);
    01566
    01567     val = solverAPI.Solve();
    01568     isSolved = solverAPI.IsSolved();
    01569     isOptimal = solverAPI.IsOptimal();
    01570     //On appelle le solveur sur le fichier LP
    01571
    01572     // appel de SetNumVarValues
    01573     // pour stocker les résultat des varialbes
    01574     SetNumVarValues(solverAPI.GetNumVarNoms(), solverAPI.OutNumVarValues());
    01575     // appel de SetConstraintValues
    01576     // pour stocker les résultat des contraintes
    01577     SetConstraintValues( solverAPI.GetConstraintNoms(), solverAPI.OutConstraintValues() );
    01578     //on sauve la valeur de la fonction objecitf
    01579     objectifActivity = val + objectif.GetConstant();
    01580     return objectifActivity;
    01581 }
    01582
    01588 void Model::GetInfluentLagrangianParam( list<LagrangianParam> & listViolated, list<LagrangianParam> & listSlacked)
    01589 {
    01590      map<VarId,InternalConstraint>::iterator constraint = constraintMap.begin();
    01591      //Pour toutes les contraintes
    01592      for(;constraint != constraintMap.end(); ++constraint)
    01593      {
    01594           float ecart = constraint->second.b - constraint->second.activity;
    01595           //on calcule la variable d'écart
    01596           if( ecart < 0 )
    01597              listViolated.push_back( LagrangianParam(*this,constraint->first) );
    01598              //la contrainte est violée
    01599           if( ecart > 0 )
    01600              listSlacked.push_back( LagrangianParam(*this,constraint->first) );
    01601              //la contrainte est lache
    01602      }
    01603 }
    01604
    01608 std::vector<LagrangianParam> Model::GetAllLagrangianParams( )
    01609 {
    01610     vector<LagrangianParam> retour;
    01611     //le vecteur de retour
    01612     map<VarId,InternalConstraint>::iterator constraint = constraintMap.begin();
    01613     //on parcourt le map des contraintes
    01614     for(;constraint != constraintMap.end(); ++constraint)
    01615     {
    01616         retour.push_back( LagrangianParam(*this,constraint->first) );
    01617         //on ajoute le lagrangien de chaque contrainte au vecteur
    01618     }
    01619     return retour;
    01620 }
    01621
    01627 void Model::SetNumVarValues(const list<string> & noms, const list<float> & values)
    01628 {
    01629    map<string,float> resultats;
    01630    //ce map permet de gagner du temps dans la recherche sur la liste de noms
    01631    //il permet de passer d'une complexite en O(n*n) à O(n*Log(n))
    01632    //il fait correspondre une valeur à un nom de contrainte
    01633
    01634    //si le nombre de noms correspond au nombre de valeurs
    01635    if(noms.size() == values.size())
    01636    {
    01637        //on construit le map des résultats d'execution
    01638        list<string>::const_iterator iterNoms = noms.begin();
    01639        //iterateur sur la liste de noms
    01640        list<float>::const_iterator iterValues = values.begin();
    01641        //iterateur sur la liste de valeurs
    01642
    01643        //on parcout les deux listes en meme temps
    01644        //sachant qu'on est sur qu'elle font la même taille
    01645        while( iterNoms != noms.end() )
    01646        {
    01647           resultats[*iterNoms] = *iterValues;
    01648           //on cree le couple ( nom, valeur )
    01649           ++iterNoms;
    01650           ++iterValues;
    01651           //on avance dans les deux listes
    01652        }
    01653
    01654        map<string,float>::const_iterator iter;
    01655        //on parcourt le map de variables
    01656        for(map<VarId,Paire>::iterator variable  = unknowMap.begin();
    01657                                       variable != unknowMap.end();
    01658                                     ++variable)
    01659        {
    01660          iter = resultats.find(variable->second.nom);
    01661          //on cherche si le nom de la variable est dans le map de resultat
    01662          if( iter != resultats.end() )
    01663             variable->second.variable = iter->second;
    01664             //si oui on attribue la valeur
    01665          else
    01666             variable->second.variable = 0;
    01667             //sinon on la met à nul
    01668        }
    01669    }
    01670 }
    01671
    01677 void Model::SetConstraintValues(const std::list<std::string> & noms, const std::list<float> & values)
    01678 {
    01679    map<string,float> resultats;
    01680    //ce map permet de gagner du temps dans la recherche sur la liste de noms
    01681    //il permet de passer d'une complexite en O(n*n) à O(n*Log(n))
    01682    //il fait correspondre une valeur à un nom de contrainte
    01683
    01684    //si le nombre de noms correspond au nombre de valeurs
    01685    if(noms.size() == values.size())
    01686    {
    01687        //on construit le map des résultats d'execution
    01688        list<string>::const_iterator iterNoms = noms.begin();
    01689        //iterateur sur la liste de noms
    01690        list<float>::const_iterator iterValues = values.begin();
    01691        //iterateur sur la liste de valeurs
    01692
    01693        //on parcout les deux listes en meme temps
    01694        //sachant qu'on est sur qu'elle font la même taille
    01695        while( iterNoms != noms.end() )
    01696        {
    01697           resultats[*iterNoms] = *iterValues;
    01698           //on cree le couple ( nom, valeur )
    01699           ++iterNoms;
    01700           ++iterValues;
    01701           //on avance dans les deux listes
    01702        }
    01703
    01704        map<string,float>::iterator trouve;
    01705        map<VarId,InternalConstraint>::iterator constraint = constraintMap.begin();
    01706        //on parcourt le map des contraintes
    01707        for(;constraint != constraintMap.end(); ++constraint)
    01708        {
    01709             trouve = resultats.find(constraint->second.name);
    01710             //si on trouve le nom de la contrainte dans le map de resultats
    01711             if( trouve != resultats.end())
    01712                 constraint->second.activity = trouve->second;
    01713                 //on lui attribue sa valeur
    01714             else
    01715                 constraint->second.activity = EvalConstraint(constraint->first);
    01716                 //sinon on la calcule
    01717        }
    01718    }
    01719    else
    01720    {
    01721       cerr << "Warning in Model::SetConstraintValues : list dimension problem, ";
    01722       if( noms.size() <= values.size() )
    01723           cerr << "the first param is too large" << endl;
    01724       else
    01725           cerr << "the second param is too large" << endl;
    01726    }
    01727
    01728 }
    01729
    01733 std::ostream & Model::OutNumVarValues( bool withoutNullValue,std::ostream & flux, const std::string & newline) const
    01734 {
    01735     float t=0.0;
    01736     string strInf = "Infinity";
    01737     if( newline == "<br/>")
    01738       strInf = "<em>oo</em>";
    01739     else if( newline == "\\\\")
    01740            strInf = "$\\infty$";
    01741
    01742
    01743     flux << "Valeurs des variables (type et domaine de définition):" << newline << endl;
    01744     //on parcourt le map des variables et on affiche celles qui sont non nulles
    01745     //s'il y a l'option withoutNullValue
    01746     for(map<VarId,Paire>::const_iterator variable  = unknowMap.begin();
    01747                                           variable != unknowMap.end();
    01748                                         ++variable)
    01749     {
    01750         if ( (t = (variable->second.variable.GetValue())) || !withoutNullValue)
    01751         {
    01752             int n=1,s=1;
    01753             float e=0;
    01754             float residu=0.0;
    01755             unsigned d=1;
    01756             bool aviableResidu = false;
    01757
    01758             if (isFract==true)
    01759             {
    01760                s = (t<0.0?-1:1);
    01761                e = floor(t);
    01762                residu = t - e;
    01763                aviableResidu = _fract.Approx(residu,n,d);
    01764             }
    01765             flux << variable->second.nom << " = ";
    01766              if (isFract==true && aviableResidu==true)
    01767              {
    01768                if (s<0)
    01769                   flux << '-' << (e!=0?e:' ') << '-' << n<<'/'<<d;
    01770                else
    01771                   flux << (e!=0?e:' ') << '+' << n << '/' << d;
    01772              }
    01773              else
    01774                flux << t;
    01775             // Affichage des bornes
    01776             float uB = variable->second.variable.GetUpperBound();
    01777             float lB = variable->second.variable.GetLowerBound();
    01778             ostringstream sstr_lB; sstr_lB << lB;
    01779             ostringstream sstr_uB; sstr_uB << uB;
    01780             string type;
    01781
    01782             switch(variable->second.variable.GetType())
    01783             {
    01784               case MuteVar::INT:   type = "INT";   break;
    01785               case MuteVar::FLOAT: type = "FLOAT"; break;
    01786               case MuteVar::BOOL:  type = "BOOL";  break;
    01787               default:
    01788                     cerr << "Warning in Model::OutNumVarValues : Error type of variable in switch statement " << endl;
    01789                 break;
    01790             }
    01791
    01792             flux << "  ........ "<< type <<" ....... [" << (lB==-Infinity?"-"+strInf : sstr_lB.str()) << ',' << (uB==Infinity ? "+"+strInf : sstr_uB.str()) << ']';
    01793             flux << newline << endl;
    01794         }
    01795     }
    01796     return flux;
    01797 }
    01798
    01800 std::ostream & Model::OutConstraintValues(std::ostream & flux, const std::string & newline ) const
    01801 {
    01802      flux << "Caracteristiques des constraintes (si non toutes saturées): " << newline << endl;
    01803      map<VarId,InternalConstraint>::const_iterator constraint = constraintMap.begin();
    01804      //on parcourt le map de contraintes
    01805      string op[]  = { "<=",">=","=",">","<"};
    01806
    01807      for(;constraint != constraintMap.end(); ++constraint)
    01808      {
    01809             //on affiche la valeur de la contrainte apres execution
    01810
    01811             float ecart = constraint->second.b - constraint->second.activity;
    01812             if(  constraint->second.type == InternalConstraint::SUP
    01813               || constraint->second.type == InternalConstraint::SUPSTRICT )
    01814                 ecart = -ecart;
    01815
    01816
    01817             // Conversion en fraction
    01818             int n=1,s=1;
    01819             float e=0;
    01820             float residu=0.0;
    01821             unsigned d=1;
    01822             bool aviableResidu = false;
    01823
    01824             if (isFract==true)
    01825             {
    01826                s = (ecart<0.0?-1:1);
    01827                e = floor(ecart);
    01828                residu = (s<0 ? (-ecart)-e : ecart-e);
    01829                aviableResidu = _fract.Approx(residu,n,d);
    01830             }
    01831             //on regarde la variable d'écart et on étudie les trois cas qui se présentent
    01832             if ( -1e-10 >= ecart || ecart >= 1e-10)
    01833             {
    01834                 flux << constraint->second.name << " = " << constraint->second.activity;
    01835
    01836                 if( ecart > 0 ) {
    01837                    if (isFract==true && aviableResidu==true)
    01838                    {
    01839                      if (s<0)
    01840                         flux << (e!=0.0?'-'<<int(e):' ') << '-' << n<<'/'<<d;
    01841                      else
    01842                         flux << (e!=0.0?e:' ') << '+' << n << '/' << d;
    01843                    }
    01844                    else
    01845                      flux << " " <<op[constraint->second.type] << " "
    01846                      << constraint->second.b << " ... non saturee ecart : " << ecart
    01847                      << newline << endl;
    01848                 }
    01849                 else {
    01850                    if (isFract==true && aviableResidu==true)
    01851                    {
    01852                      flux << "contrainte ecart: ";
    01853                      if (s<0)
    01854                         flux << (e!=0.0?'-'<<int(e):' ') << '-' << n<<'/'<<d;
    01855                      else
    01856                         flux << (e!=0.0?e:' ') << '+' << n << '/' << d;
    01857                    }
    01858                    else
    01859                      flux << " " <<op[constraint->second.type] << " "
    01860                      << constraint->second.b << " ... violee ecart : " << ecart
    01861                      << newline << endl;
    01862                 }
    01863
    01864             }
    01865      }
    01866      return flux;
    01867 }
    01868
    01874 bool Model::LoadLP(const std::string& _name, bool verbose)
    01875 {
    01876     FichierLP file;
    01877     //on déclare un fichier LP source
    01878
    01879     //si on ne reussi pas à charger le fichier LP
    01880     if(!file.Open(_name.c_str()))
    01881     {
    01882         cerr << "Warning in Model::LoadLP : I/O error in the opening of " << _name << endl;
    01883         return false;
    01884         //on quitte
    01885     }
    01886
    01887     //sinon on charge le modèle à partir du fichier LP
    01888     if( file >> (*this) )
    01889     {
    01890         //si le flag d'affichage est vrai
    01891         if(verbose == true)
    01892         {
    01893             cout << file << endl;
    01894             //on affiche
    01895         }
    01896         return true;
    01897     }
    01898     return false;
    01899 }
    01900
    01906 bool Model::LoadMPS(const std::string& _name, bool verbose)
    01907 {
    01908     FichierMPS file;
    01909     //on déclare un fichier LP source
    01910
    01911     //si on ne reussi pas à charger le fichier LP
    01912     if(!file.Open(_name.c_str()))
    01913     {
    01914         cerr << "Warning in Model::LoadLP : I/O error in the opening of " << _name << endl;
    01915         return false;
    01916         //on quitte
    01917     }
    01918
    01919     //sinon on charge le modèle à partir du fichier LP
    01920     if( file >> (*this) )
    01921     {
    01922         //si le flag d'affichage est vrai
    01923         if(verbose == true)
    01924         {
    01925             cout << file << endl;
    01926             //on affiche
    01927         }
    01928         return true;
    01929     }
    01930     return false;
    01931 }
    01932
    01936 void Model::ShowMe( bool withoutNullValue)
    01937 {
    01938      OutNumVarValues(withoutNullValue);
    01939      OutConstraintValues();
    01940 }
    01941
    01945 void Model::RemoveVariable(VarId varId)
    01946 {
    01947    map<VarId,Paire>::iterator variable = unknowMap.find(varId);
    01948    //on regarde si l'identifiant existe
    01949    if( variable != unknowMap.end() )
    01950    {
    01951      unknowMap.erase( variable );
    01952      //on efface la variable associée puis on nettoie la matrice creuse
    01953
    01954      std::map< Id,float,Compare<float> >::iterator iter  = A.matrix.begin();
    01955      std::map< Id,float,Compare<float> >::iterator tmp;
    01956
    01957      //on parcourt la matrice
    01958      while(iter != A.matrix.end())
    01959      {
    01960        unsigned i = iter->first.i; //indice de colonne
    01961
    01962        //si l'on se trouve sur la colonne de la matrice creuse
    01963        if(i == varId)
    01964        {
    01965         //dans de ca on supprime l'element
    01966         tmp = iter;
    01967         //mais pas directement car erase ne retourne la position du prochain élément
    01968         ++iter;
    01969         //donc on avance
    01970         A.matrix.erase( tmp );
    01971         //et ensuite on supprime
    01972        }
    01973        else
    01974           ++iter;
    01975           //sinon on se contente d'avancer
    01976      }
    01977    }
    01978    else
    01979      cerr << "Warning in Model::RemoveVariable : undefined id " << varId << endl;
    01980
    01981 }
    01982
    01986 void Model::RemoveConstraint(VarId id)
    01987 {
    01988
    01989   std::map< Id,float,Compare<float> >::iterator iter  = A.matrix.begin();
    01990   //iterateur principal qui va parcourir le map matrix de A
    01991   std::map< Id,float,Compare<float> >::iterator tmp;
    01992   //iterateur secondaire qui sert à sauvegarder les positions à supprimer
    01993   //tant que l'on a pas fini de percourir le map
    01994   while(iter != A.matrix.end())
    01995   {
    01996      unsigned j = iter->first.j;
    01997      //on recupere l'indice horizontale de l'élément courant
    01998      //on le compare avec l'identifiant de la contrainte
    01999      if(j == id)
    02000      {
    02001         //dans de ca on supprime l'element
    02002         tmp = iter;
    02003         //mais pas directement car erase ne retourne la position du prochain élément
    02004         ++iter;
    02005         //donc on avance
    02006         A.matrix.erase( tmp );
    02007         //et ensuite on supprime
    02008      }
    02009      else
    02010      {
    02011        //sinon on n'est pas sur la bonne contrainte
    02012        ++iter;
    02013        //on avance
    02014        //sauf si on a passé la contrainte
    02015        if(j>id)
    02016          //dans ce cas on quitte la boucle
    02017          break;
    02018      }
    02019   }
    02020 }
    02021
    02026 void Model::AddToConstraint(VarId id ,const Expr & expr)
    02027 {
    02028    std::list<ExprNode>::const_iterator iter;
    02029    //itérateur constant sur l'expression expr constante
    02030    //si la contrainte existe
    02031    if( constraintMap.find(id) != constraintMap.end() )
    02032    {
    02033      //on parcourt l'expression
    02034      for( iter = expr.nodeList.begin(); iter != expr.nodeList.end(); ++iter)
    02035      {
    02036         float coef = iter->GetCoefficient().GetValue();
    02037         NumVar varTmp = iter->GetVariable();
    02038         VarId varId = (varTmp.GetModel()?varTmp.GetVarId():0);
    02039         //on récupere l'identifiant de la variable
    02040         //si il est non nul et que la variable est définie
    02041         if(varId && unknowMap.find(varId) != unknowMap.end() )
    02042         {
    02043           float acoef = A.Get(varId,id);
    02044           //on récupère le coeffictient dans la matrice
    02045           //si il est différent de l'opposé du nouveau coefficient
    02046           if(acoef != -coef)
    02047             A.Set(varId,id,coef+acoef);
    02048             //coef <- coef + nouveau coef
    02049           else
    02050             A.matrix.erase(A.matrix.find(Id(varId,id)));
    02051             //sinon le coef devient nul et donc on le supprime
    02052         }
    02053         else
    02054         {
    02055            if( varId )
    02056               cerr << "Warning in Model::AddToConstraint : undefined varId " << varId << endl;
    02057         }
    02058       }
    02059    }
    02060    else
    02061      cerr << "Warning in Model::AddToConstraint : undefined constraint id " << id << endl;
    02062 }
    02063
    02068 Constraint Model::GetConstraint(const string & name)
    02069 {
    02070   //on cherche son identifiant puis on renvoie la contrainte
    02071   return GetConstraint(GetConstraintId(name));
    02072 }
    02073
    02081 VarId Model::GetConstraintId(const string & name)
    02082 {
    02083     bool trouve = false; //booléen servant de "break" à la boucle de recherche
    02084
    02085     VarId id = 0; //l'identifiant est nul si on ne trouve pas de contrainte
    02086
    02087     map<VarId,InternalConstraint>::iterator constraint = constraintMap.begin();
    02088     //iterateur de map initialisé au début
    02089     //tant que l'on a pas trouvé ou qu'il reste des contraintes à tester
    02090     while(!trouve && constraint != constraintMap.end() )
    02091     {
    02092         //on verifie si l'on a trouvé la contrainte suivante
    02093         if( ( constraint->second.name == name) )
    02094         {
    02095           id = constraint->first;
    02096           //on récupère l'identifiant de la contrainte qui est la clé dans le constraintMap
    02097           trouve = true;
    02098           //on quitte la boucle a la fin de cette itération
    02099         }
    02100         ++constraint;
    02101         //on passe à la contrainte suivante
    02102     }
    02103     return id;
    02104 }
    02105
    02110 void Model::RenameConstraint( VarId id, const string & name)
    02111 {
    02112     map<VarId,InternalConstraint>::iterator constraint = constraintMap.find(id);
    02113     //on regarde si la contrainte existe
    02114     if( constraint != constraintMap.end())
    02115         //si oui on reattribue le nom
    02116         constraint->second.name = name;
    02117     else
    02118         cerr << "Warning in Model::RenameConstraint : undefined id " << id << endl;
    02119 }
    02120
    02125 void Model::SetSecondMember(VarId id ,float bid)
    02126 {
    02127     map<VarId,InternalConstraint>::iterator constraint = constraintMap.find(id);
    02128     //on regarde si la contrainte existe
    02129     if( constraint != constraintMap.end())
    02130         //si oui on change le coefficient
    02131         constraint->second.b = bid;
    02132     else
    02133         cerr << "Warning in Model::RenameConstraint : undefined id " << id << endl;
    02134 }
    02135
    02140 float Model::GetSecondMember(VarId id) const
    02141 {
    02142     map<VarId,InternalConstraint>::const_iterator constraint = constraintMap.find(id);
    02143     //on regarde si la contrainte existe
    02144     if( constraint != constraintMap.end())
    02145         //si oui on change le coefficient
    02146         return constraint->second.b;
    02147     else
    02148         cerr << "Warning in Model::RenameConstraint : undefined id " << id << endl;
    02149     return Infinity;
    02150 }
    02151
    02153 void Model::Clear()
    02154 {
    02155     hacheVarId=1;
    02156     hacheConstraintId=1;
    02157     unknowMap.clear();
    02158     A.matrix.clear();
    02159     A.nbLignes = A.nbCols = 0;
    02160     constraintMap.clear();
    02161     comments.clear();
    02162
    02163     isMax = true;
    02164     isRelaxed = false;
    02165     isFract = false;
    02166     isOptimal = false;
    02167     isSolved = false;
    02168     isNormalized = false;
    02169     MIPVar = 0;
    02170
    02171     objectif = Expr();
    02172     objectifActivity = 0.0f;
    02173     objectifName = "";
    02174     problemName = "";
    02175 }
    02176
    02177 void Model::Normalize(bool withoutStrict)
    02178 {
    02179     unsigned p = A.GetNbLignes()+1;
    02180     float coef = 1.0f;
    02181
    02182     if(isMax==true)
    02183     {
    02184         objectif*=-1;
    02185         isMax=false;
    02186     }
    02187
    02188
    02189     map<VarId,InternalConstraint>::iterator constraint;
    02190     for(map< Id,float,Compare<float> >::iterator iter  = A.matrix.begin();
    02191                                                  iter != A.matrix.end();
    02192                                                ++iter)
    02193     {
    02194         unsigned i = iter->first.i; //indice de colonne
    02195         unsigned j = iter->first.j; //indice de ligne
    02196         if( p != j)
    02197         {
    02198             constraint = constraintMap.find(j);
    02199             switch( constraint->second.type )
    02200             {
    02201                 case InternalConstraint::SUP :
    02202                     coef = 1.0f;
    02203                 break;
    02204
    02205                 case InternalConstraint::SUPSTRICT :
    02206                     coef = 1.0f;
    02207                     constraint->second.type = InternalConstraint::SUP;
    02208                 break;
    02209
    02210                 case InternalConstraint::INF :
    02211                     coef = -1.0f;
    02212                     constraint->second.type = InternalConstraint::SUP;
    02213                 break;
    02214
    02215                 case InternalConstraint::INFSTRICT :
    02216                     coef = -1.0f;
    02217                     constraint->second.type = InternalConstraint::SUP;
    02218                 break;
    02219                 case InternalConstraint::EGAL :
    02220                     coef = 1.0;
    02221                 break;
    02222                 default:
    02223                 break;
    02224              }
    02225              constraint->second.b*=coef;
    02226              p = j;
    02227         }
    02228         map<VarId,Paire>::iterator variable =  unknowMap.find(i);
    02229         if( variable->second.variable.GetLowerBound() >=0 )
    02230             iter->second*=coef;
    02231         else
    02232             iter->second*=-coef;
    02233     }
    02234      map<VarId,Paire>::iterator variable;
    02235      for(variable = unknowMap.begin();variable != unknowMap.end();++variable)
    02236      {
    02237         if( !(variable->second.variable.GetLowerBound() >=0 ))
    02238         {
    02239            float lb = variable->second.variable.GetLowerBound();
    02240            float ub = variable->second.variable.GetUpperBound();
    02241            variable->second.variable.SetLowerBound(-ub);
    02242            variable->second.variable.SetUpperBound(-lb);
    02243         }
    02244      }
    02245
    02246 }
    02247
    02248
    02249
    02250
    02254 Model Model::GetDual() const
    02255 {
    02256     Model ret;
    02257     map<VarId,Paire>::const_iterator variable;
    02258     map<VarId,InternalConstraint>::const_iterator constraint;
    02259
    02260     ret.isMax = !isMax;
    02261     ret.solverAPI = solverAPI;
    02262     ret.objectifName = objectifName + "dual";
    02263     ret.problemName = problemName + "dual";
    02264
    02265     for(map< Id,float,Compare<float> >::const_iterator iter  = A.matrix.begin();
    02266                                                          iter != A.matrix.end();
    02267                                                        ++iter)
    02268     {
    02269
    02270         unsigned i = iter->first.i; //indice de colonne
    02271         unsigned j = iter->first.j; //indice de ligne
    02272         float coef = iter->second;
    02273         ret.A.Set(j,i,coef);
    02274     }
    02275
    02276     for(constraint = constraintMap.begin(); constraint != constraintMap.end(); ++constraint)
    02277     {
    02278        unsigned id = constraint->first;
    02279        Paire var;
    02280        InternalConstraint ic = constraint->second;
    02281        var.nom = ic.name;
    02282        float lb=0,ub=Infinity;
    02283        var.variable = MuteVar( MuteVar::FLOAT,ic.activity,lb,ub);
    02284        ret.unknowMap[id] = var;
    02285        ret.objectif += ic.b * NumVar( const_cast<const Model *>(&ret), id);
    02286      }
    02287
    02288     for(variable = unknowMap.begin(); variable != unknowMap.end(); ++variable)
    02289     {
    02290        unsigned id = variable->first;
    02291        ret.constraintMap[id] = InternalConstraint( InternalConstraint::INF,
    02292                                                    0.0,
    02293                                                    variable->second.variable.GetValue(),
    02294                                                    0.0,
    02295                                                    variable->second.nom);
    02296
    02297     }
    02298
    02299     for( list<ExprNode>::const_iterator iter = objectif.nodeList.begin();
    02300                                         iter != objectif.nodeList.end();
    02301                                       ++iter)
    02302     {
    02303         float b = iter->GetCoefficient().GetValue();
    02304         unsigned id = iter->GetVariable().GetVarId();
    02305         ret.SetSecondMember(id,b);
    02306     }
    02307
    02308     return ret;
    02309 }
    02310
    02314 void Model::PrintDual(const std::string& fileName) const
    02315 {
    02316     ofstream file( fileName.c_str() );
    02317     if(!file.is_open())
    02318         throw runtime_error("Model::PrintDual : I/O Error");
    02319     file << GetDual();
    02320     file.close();
    02321 }
    02322
    02323
    02330 std::string Model::AddComment( const std::string & comment )
    02331 {
    02332   std::map<VarId,std::string>::iterator trouve = comments.find(hacheConstraintId);
    02333   std::string retour;
    02334   if(trouve!=comments.end())
    02335   {
    02336     retour = trouve->second;
    02337     trouve->second = comment;
    02338   }
    02339   else
    02340     comments[hacheConstraintId] = comment;
    02341   return retour;
    02342 }
    02343
    02349 void Model::SetComment( VarId id, const std::string &  comment)
    02350 {
    02351   std::map<VarId,std::string>::iterator trouve = comments.find(id);
    02352   if(trouve!=comments.end())
    02353      trouve->second = comment;
    02354   else
    02355      comments[id] = comment;
    02356 }
    02357
    02358 std::string Model::GetComment( VarId id ) const
    02359 {
    02360   std::map<VarId,std::string>::const_iterator trouve = comments.find(id);
    02361   if(trouve!=comments.end())
    02362      return trouve->second;
    02363   else
    02364      return std::string();
    02365 }
    02366
    02367
    02368 #ifdef USE_HTML_FORMAT
    02369
    02372 void Model::SortieHTML( const std::string & fileName, const std::string& matrixPNG)
    02373 {
    02374     HTMLFile html(fileName);
    02375     std::ostream & out = html.getStream();
    02376     string s1,s2;
    02377     SolveInfos(s1,s2);
    02378
    02379     // Si ce n'est pas résolu, on l'affiche en gros et en haut
    02380     if (isSolved == false)
    02381     {
    02382         html << "<h3>Problème non résolu</h3>";
    02383         html.NewLine();
    02384     }
    02385
    02386     // Entete html/liens
    02387     html << "<h1>Sortie du Modèle du Programme linéaire</h1>";
    02388     html << "<ul>";
    02389     html << "<li><a href=\"#caracteristique_probleme\">Caractéristiques du problème</a></li>";
    02390     html << "<li><a href=\"#dimension_probleme\">Dimensions du problème</a></li>";
    02391     if( A.GetNbLignes() < 20 && A.GetNbCols() < 20)
    02392       html << "<li><a href=\"#pl\">Programme linéaire</a></li>";
    02393     if( isSolved )
    02394       html << "<li><a href=\"#resolution\">Résolution du problème</a></li>";
    02395     if (matrixPNG != "")
    02396       html << "<li><a href=\"#matrice_creuse\">Affichage de la matrice creuse</a></li>";
    02397
    02398     html << "</ul>";
    02399     html.NewLine();
    02400     html << "<h2><a name=\"caracteristique_probleme\">Caractéristiques du problème</a></h2>";
    02401
    02402     html << "Problème de <b>" << s1 << "</b>";
    02403     html.NewLine();
    02404     if( problemName != "" )
    02405     {
    02406         html << "Nom du problème: \"" << problemName << "\"";
    02407         html.NewLine();
    02408     }
    02409     if( objectifName != "" )
    02410     {
    02411       html << "Nom de la fonction objectif: <b>" << objectifName << "</b>";
    02412       html.NewLine();
    02413     }
    02414     html << "<br />";
    02415     html << "<h2><a name=\"dimension_probleme\">Dimensions du problème</a></h2>";
    02416     html.NewLine();
    02417     OutDimensions(out,"<br/>");
    02418     html << "<br />";
    02419     // Sortie du LP dans le fichier HTML
    02420     if( A.GetNbLignes() < 20 && A.GetNbCols() < 20)
    02421     {
    02422         html << "<h2><a name=\"pl\">Programme linéaire</a></h2>";
    02423         html << *this;
    02424         html << "<br />";
    02425     }
    02426     if( isSolved )
    02427     {
    02428         html << "<h2><a name=\"resolution\">Résolution du problème</a></h2>";
    02429         html.NewLine();
    02430         html << "Le problème a été résolu avec " << (solverAPI.GetAPI()==1?"GLPSOL" : "CPLEX");
    02431         html.NewLine();
    02432         html.NewLine();
    02433         if (isRelaxed) {
    02434            html << "Le problème est relaxé";
    02435            html.NewLine();
    02436         }
    02437         if( isOptimal )
    02438             html << "Solution <b>OPTIMALE</b>: " << objectifActivity;
    02439         else
    02440             html << "Solution NON OPTIMALE: " << objectifActivity;
    02441         html.NewLine();
    02442         html << "Sortie solveur: " << s2;
    02443
    02444         html.NewLine();
    02445         html.NewLine();
    02446         OutNumVarValues(true,out,"<br/>");
    02447         html.NewLine();
    02448         OutConstraintValues(out,"<br/>");
    02449         html.NewLine();
    02450
    02451         // Si on a sorti un matrice creuse, on peut la mettre dans le fichier HTML
    02452         #ifdef EXPORT_SPARSE_MATRIX_PNG
    02453         if (matrixPNG != "")
    02454         {
    02455             html << "<h2><a name=\"matrice_creuse\">Affichage de la matrice creuse</a></h2>";
    02456             html << "<div align='center'>";
    02457             html << "<img src='./" << matrixPNG << "' alt\"MatriceCreuse\"/>";
    02458             html << "</div>";
    02459             html.NewLine();
    02460         }
    02461         #endif
    02462     }
    02463     html.Close();
    02464 }
    02465 #endif
    02466
    02467 #ifdef USE_LATEX_FORMAT
    02468
    02471 void Model::SortieLATEX( const std::string & fileName)
    02472 {
    02473     LATEXFile latex(fileName,"Programme linéaire",false);
    02474     std::ostream & out = latex.getStream();
    02475     latex << "Sortie du Modele du Programme linéaire";
    02476     latex.MakeSection("Caractéristiques du problème");
    02477
    02478     if( problemName != "" )
    02479     {
    02480         latex.MakeSection("Nom du problème:");
    02481         latex << "  Le nom du probleme est" << problemName;
    02482         latex.EndSection();
    02483     }
    02484     latex.MakeSection( "Dimensions du problème:");
    02485     OutDimensions(out,"\\\\");
    02486     latex.EndSection();
    02487     latex.EndSection();
    02488     if( A.GetNbLignes() < 20 && A.GetNbCols() < 20)
    02489     {
    02490         latex.MakeSection( "Programme linéaire");
    02491         latex << *this;
    02492         latex.EndSection();
    02493     }
    02494     if( isSolved )
    02495     {
    02496         latex.MakeSection( "Résolution du problème");
    02497         latex.MakeSection( "Fonction Objectif");
    02498         if( isOptimal )
    02499             latex << "Solution OPTIMALE: " << objectifActivity;
    02500         else
    02501             latex << "Solution NON OPTIMALE: " << objectifActivity;
    02502         latex.EndSection();
    02503
    02504         latex.MakeSection( "Variables");
    02505         OutNumVarValues(true,out,"\\\\");
    02506         latex.EndSection();
    02507         latex.MakeSection( "Contraintes");
    02508         OutConstraintValues(out,"\\\\");
    02509         latex.EndSection();
    02510     }
    02511     else
    02512     {
    02513         latex << "Problème non résolu";
    02514     }
    02515     latex.Close();
    02516 }
    02517 #endif
    02518
    02519 #ifdef EXPORT_SPARSE_MATRIX_PNG
    02520
    02521   #include "Png.h"
    02522
    02523   void Model::ExportSparseMatrixPNG(const std::string& _nom) const
    02524   {
    02525     // Obtenir la dimension de la matrice
    02526     unsigned w=A.GetNbCols(),h=A.GetNbLignes();
    02527     // définir une quantité de Zoom sur l'image p-ê
    02528     unsigned zoom=1;
    02529
    02530     PNGImage image(_nom.c_str(), w, h);
    02531     image.openFileWrite();
    02532     image.initWriteStructs();
    02533     image.writeHeader();
    02534     png_byte **Buff = image.writeImage_Start();
    02535     unsigned char col1=255,col2=255,col3=255;
    02536
    02537     for (unsigned y=0;y<h;y+=zoom)
    02538         for (unsigned x=0;x<w;x+=zoom)
    02539         {
    02540           float val = A(x,y);
    02541             col2 = 65;
    02542             //cout << scaled << " <-> " << val << " | ";
    02543             if (val < -epsylon)    {col1 = 255; col3=0;} // rouge = négatif
    02544             else if(val > epsylon) {col1=0; col3 = 255;} // bleu  = positif
    02545             else
    02546             {
    02547               col1=col2=col3=255;
    02548             }
    02549           Buff[y][x*3+0] = col1;
    02550           Buff[y][x*3+1] = col2;
    02551           Buff[y][x*3+2] = col3;
    02552         }
    02553
    02554     image.writeImage_End();
    02555     image.writeEnd();
    02556   }
    02557
    02558 #endif
    02559
    02560 #ifdef COMPILE_FOR_PYTHON
    02561     #include "py_Model.cxx"
    02562 #endif
    02563
    02564
    02565 }