00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "Config.h"
00034 #include "FichierLP.h"
00035 #include <iostream>
00036 #include <fstream>
00037 #include <sstream>
00038 #include <list>
00039 #include <string>
00040 #include <algorithm>
00041 #include <cctype>
00042 #include <map>
00043 #include <utility>
00044 #include <vector>
00045
00046 namespace Modelib {
00047
00048 using namespace std;
00049
00050
00059 ostream& operator<<(ostream &o, const string& str)
00060 {
00061 for (string::const_iterator iter=str.begin();iter!=str.end();++iter)
00062 {
00063
00064 if (*iter < 32)
00065 continue;
00066 o << *iter;
00067 }
00068 return o;
00069 }
00070
00076 ostream& operator<<(ostream &o, const plExprNode& pl)
00077 {
00078 o << (pl.signe == MINUS ? '-' : '+') << pl.num << "*" << pl.var;
00079 return o;
00080 }
00081
00087 ostream& operator<<(ostream &o, const plGlobalNode& pl)
00088 {
00089 if (pl.nom != "")
00090 o << pl.nom << ": ";
00091 for (list<plExprNode *>::const_iterator iter = pl.expr.begin();iter!=pl.expr.end(); ++iter)
00092 {
00093 if (iter == pl.expr.begin())
00094 o << ((*iter)->signe == MINUS ? "-" : " ") << (*iter)->num << '*' << (*iter)->var << ' ';
00095 else
00096 o << **iter;
00097 }
00098 o << " " << comp[pl.cont.comp] << " " << pl.cont.bound;
00099 return o;
00100 }
00101
00102
00108 ostream& operator<<(ostream& o, const plConstraintNode& pl)
00109 {
00110 o << pl.minBound << " ";
00111 o << comp[pl.comp1] << " ";
00112 if (pl.num != "1")
00113 o << pl.num << "*";
00114 o << pl.var;
00115
00116 if (pl.comp2 != 99)
00117 o << comp[pl.comp2] << " " << pl.maxBound;
00118
00119 return o;
00120 }
00121
00140 ostream& operator<<(ostream &o, const FichierProbleme& pblm)
00141 {
00142 o << "\\Sortie du fichier de probleme: " << pblm.nom << endl;
00143
00144
00145 if (pblm.isMax == true)
00146 o << "Maximize" << endl;
00147 else
00148 o << "Minimize" << endl;
00149
00150 for (list<plExprNode *>::const_iterator iter = pblm.exprObj.begin();
00151 iter != pblm.exprObj.end() ;
00152 ++iter)
00153 if (iter == pblm.exprObj.begin() && (*iter)->var.length())
00154 o << "\t" << ((*iter)->signe == MINUS ? "-" : " ") << (*iter)->num << "*" << (*iter)->var << ' ';
00155 else
00156 o << **iter;
00157
00158
00159 o << endl;
00160 o << "Subject to" << endl;
00161
00162
00163 for (list<plGlobalNode *>::const_iterator iter = pblm.exprConstraint.begin();
00164 iter != pblm.exprConstraint.end() ;
00165 ++iter)
00166 o << "\t" << **iter << endl;
00167
00168 if (!pblm.exprBounds.empty())
00169 {
00170 o << "Bounds" << endl;
00171
00172
00173 for (list<plConstraintNode *>::const_iterator iter = pblm.exprBounds.begin();
00174 iter != pblm.exprBounds.end() ;
00175 ++iter)
00176 o << "\t" << **iter << endl;
00177 }
00178 if (!pblm.exprGeneral.empty())
00179 {
00180 o << "Generals" << endl;
00181 for (list<string>::const_iterator iter =pblm.exprGeneral.begin();
00182 iter!=pblm.exprGeneral.end() ;
00183 ++iter)
00184 o << "\t" << *iter << endl;
00185 }
00186
00187 if (!pblm.exprBinary.empty())
00188 {
00189 o << "Binaries" << endl;
00190 for (list<string>::const_iterator iter =pblm.exprBinary.begin();
00191 iter!=pblm.exprBinary.end() ;
00192 ++iter)
00193 o << "\t" << *iter << endl;
00194 }
00195
00196 o << "End";
00197 return o;
00198 }
00199
00200
00201
00209 FichierLP::FichierLP()
00210 {
00211
00212 mmap.insert(pair<string,unsigned>("maximize",MAXIMIZE));
00213 mmap.insert(pair<string,unsigned>("max",MAXIMIZE));
00214
00215 mmap.insert(pair<string,unsigned>("minimize",MINIMIZE));
00216 mmap.insert(pair<string,unsigned>("min",MINIMIZE));
00217
00218 mmap.insert(pair<string,unsigned>("subject to",SUBJECT));
00219 mmap.insert(pair<string,unsigned>("subject",SUBJECT));
00220 mmap.insert(pair<string,unsigned>("such that",SUBJECT));
00221 mmap.insert(pair<string,unsigned>("st",SUBJECT));
00222 mmap.insert(pair<string,unsigned>("st.",SUBJECT));
00223 mmap.insert(pair<string,unsigned>("s.t.",SUBJECT));
00224
00225 mmap.insert(pair<string,unsigned>("bounds",BOUNDS));
00226 mmap.insert(pair<string,unsigned>("bound",BOUNDS));
00227
00228 mmap.insert(pair<string,unsigned>("end",END));
00229
00230 mmap.insert(pair<string,unsigned>("generals",GENERALS));
00231 mmap.insert(pair<string,unsigned>("general",GENERALS));
00232 mmap.insert(pair<string,unsigned>("gen",GENERALS));
00233 mmap.insert(pair<string,unsigned>("integers",GENERALS));
00234 mmap.insert(pair<string,unsigned>("integer",GENERALS));
00235
00236 mmap.insert(pair<string,unsigned>("binaries",BINARIES));
00237 mmap.insert(pair<string,unsigned>("binary",BINARIES));
00238 mmap.insert(pair<string,unsigned>("bin",BINARIES));
00239
00240 mmap.insert(pair<string,unsigned>("free",FREE));
00241
00242
00243 for (unsigned i=0;i<6;i++)
00244 Comp2Int[comp[i]] = i;
00245 }
00246
00251 bool FichierLP::IsComment(string& s)
00252 {
00253
00254
00255 string::iterator iter = s.begin();
00256 string tmp;
00257
00258 if (*iter == '\\') {
00259 commentaires.push_back( pair<long,string>( (long)exprConstraint.size()
00260 + ( exprObj.size()==0?0:1) ,s) );
00261 return true;
00262 }
00263
00264 for (;iter!=s.end();++iter)
00265 {
00266 if (*iter == '\\')
00267 break;
00268 tmp += *iter;
00269 }
00270 s.erase();
00271 s = tmp;
00272 return false;
00273 }
00274
00279 string FichierLP::trim(const string& s) const
00280 {
00281 if(s.empty())
00282 return s;
00283 int b = s.find_first_not_of(" ");
00284 int e = s.find_last_not_of(" ");
00285 if(b == -1)
00286 return "";
00287 return string(s, b, e - b + 1);
00288 }
00289
00294 string FichierLP::AvoidSpaces(const string& s) const
00295 {
00296 string t;
00297 string::const_iterator iter = s.begin();
00298 for(;iter!=s.end();++iter)
00299 if (*iter != ' ')
00300 t += *iter;
00301 return t;
00302 }
00303
00309 bool FichierLP::IsNumber(const string& s) const
00310 {
00311 const string nums="0123456789./";
00312 string::const_iterator iter;
00313 bool pointWOSlash = false;
00314 for (iter=s.begin();iter!=s.end();++iter)
00315 {
00316 if (pointWOSlash && *iter=='.')
00317 return false;
00318 if (nums.find(*iter) != string::npos)
00319 {
00320 if (*iter == '.') pointWOSlash=true;
00321 if (*iter == '/' ) pointWOSlash=false;
00322 }
00323 else
00324 return false;
00325 }
00326 return true;
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 }
00337
00343 void FichierLP::Tokenize(const string& str,list<string>& tokens_plus
00344 ,list<string>& tokens_minus)
00345 {
00346 enum Token_Value {PLUS='+', MINUS='-'};
00347 Token_Value cur_token = PLUS;
00348 string tmp;
00349 string::size_type i=0;
00350 const string::size_type len = str.length();
00351
00352 do
00353 {
00354 while(str[i]==' ') ++i;
00355 if (str[i] == PLUS || str[i] == MINUS)
00356 {
00357 if(tmp.length())
00358 {
00359
00360 switch(cur_token)
00361 {
00362 case PLUS : tokens_plus.push_back(tmp); break;
00363 case MINUS: tokens_minus.push_back(tmp); break;
00364 default : break;
00365 }
00366
00367 tmp.clear();
00368
00369 cur_token = (str[i]=='+'?PLUS:MINUS);
00370 }
00371 else
00372 cur_token = (str[i]=='+'?PLUS:MINUS);
00373 }
00374 else
00375 tmp += str[i];
00376 ++i;
00377 }
00378 while (i < len);
00379
00380
00381 switch(cur_token)
00382 {
00383 case PLUS : tokens_plus.push_back(tmp); break;
00384 case MINUS: tokens_minus.push_back(tmp); break;
00385 default : break;
00386 }
00387 }
00388
00394 void FichierLP::GetNumVar(const string& str, string& num, string& var)
00395 {
00396 string::const_iterator iter=str.begin();
00397 unsigned i=0;
00398 if (!isdigit(*iter))
00399 {
00400 num = "1";
00401 var = str;
00402 }
00403 else
00404 {
00405 for (;iter!=str.end();++iter,++i)
00406 {
00407 if (!IsNumber(str.substr(0,i)))
00408 {
00409 num=str.substr(0,i-1);
00410 var=str.substr(i-1,str.length());
00411 break;
00412 }
00413 }
00414 }
00415 }
00416
00417
00418
00419
00423 void FichierLP::ParseObjective(const string& s)
00424 {
00425
00426 list<string> token_plus;
00427 list<string> token_minus;
00428 list<string>::iterator iter;
00429
00430 if (s.length() <= 1)
00431 return;
00432
00433 Tokenize (s,token_plus,token_minus);
00434
00435 for(iter=token_plus.begin();iter!=token_plus.end();++iter)
00436 {
00437 string var,num;
00438 GetNumVar(*iter,var,num);
00439
00440
00441
00442 auto_ptr<plExprNode> exprNode (new plExprNode (num,var,PLUS)) ;
00443 exprObj.push_back(exprNode.release());
00444 }
00445
00446 for(iter=token_minus.begin();iter!=token_minus.end();++iter)
00447 {
00448 string var,num;
00449 GetNumVar(*iter,var,num);
00450
00451
00452 auto_ptr<plExprNode> exprNode (new plExprNode (num,var,MINUS)) ;
00453 exprObj.push_back(exprNode.release());
00454 }
00455
00456
00457
00458
00459
00460
00461
00462
00463 }
00464
00465
00470 void FichierLP::ParseSubjects (const string& s, const string& nom)
00471 {
00472
00473
00474 string::size_type place_comp=string::npos;
00475 unsigned i=0;
00476
00477
00478 if (s.length() <= 1)
00479 return;
00480
00481
00482 for (;i<6;i++)
00483 {
00484 if ((place_comp = s.find(comp[i])) != string::npos)
00485 break;
00486 }
00487
00488 if (place_comp == string::npos)
00489 {
00490
00491 return;
00492 }
00493
00494 string compareTo;
00495 string second;
00496 compareTo = s.substr(place_comp+comp[i].length(),s.length());
00497 second = s.substr(0,place_comp);
00498
00499
00500
00501 list<string> token_plus;
00502 list<string> token_minus;
00503 list<string>::iterator iter;
00504 Tokenize (second,token_plus,token_minus);
00505
00506
00507
00508 list<plExprNode *> tmpObj;
00509
00510 for(iter=token_plus.begin();iter!=token_plus.end();++iter)
00511 {
00512 string var,num;
00513 GetNumVar(*iter,var,num);
00514 auto_ptr<plExprNode> exprNode (new plExprNode (num,var,PLUS)) ;
00515 tmpObj.push_back(exprNode.release());
00516 }
00517
00518 for(iter=token_minus.begin();iter!=token_minus.end();++iter)
00519 {
00520 string var,num;
00521 GetNumVar(*iter,var,num);
00522 auto_ptr<plExprNode> exprNode (new plExprNode (num,var,MINUS)) ;
00523 tmpObj.push_back(exprNode.release());
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533 plSimpleConstraint tmpConst(compareTo,i);
00534 auto_ptr<plGlobalNode> tmpNode (new plGlobalNode (nom,tmpObj,tmpConst));
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 exprConstraint.push_back(tmpNode.release());
00551 }
00552
00553
00558 unsigned GetNbComparator(const string& _str)
00559 {
00560 unsigned nbComp=0;
00561 string::size_type pos;
00562 string sub=_str;
00563
00564 for (unsigned j=0;j<6;)
00565 {
00566 if ((pos=sub.find(comp[j])) != string::npos)
00567 {
00568 nbComp++;
00569 sub = sub.substr(pos+comp[j].length(),sub.length());
00570 }
00571 else
00572 j++;
00573 }
00574 return nbComp;
00575 }
00576
00577
00585 void FichierLP::ParseBounds(const string& s)
00586 {
00587
00588
00589
00590
00591 string str;
00592
00593 if (s.length() <= 1)
00594 return;
00595
00596
00597 string::const_iterator iter,it2=s.begin(),next;
00598
00599 unsigned nbComp = GetNbComparator(s);
00600
00601
00602
00603
00604
00605 next = s.begin(); ++next;
00606 for (iter=s.begin();iter!=s.end();++iter, ++next)
00607 {
00608 switch(*iter)
00609 {
00610 case '<':
00611 case '>':
00612 str.push_back(' ');
00613 str.push_back(*iter);
00614
00615
00616 if (*next != '=')
00617 str.push_back(' ');
00618 break;
00619
00620 case '=':
00621 if (*it2 != '<' && *it2 != '>')
00622 str.push_back(' ');
00623 str.push_back(*iter);
00624 str.push_back(' ');
00625 break;
00626
00627 default:
00628 str.push_back(*iter);
00629 break;
00630 }
00631 it2 = iter;
00632 }
00633
00634 string *t = 0;
00635 if (nbComp > 0)
00636 {
00637 istringstream sstring(str);
00638 t = new string[(2*nbComp+1)];
00639
00640 for (unsigned i=0;i<(nbComp<<1) + 1;i++)
00641 {
00642 sstring >> t[i];
00643 }
00644 }
00645
00646
00647
00648
00649 switch (nbComp)
00650 {
00651 case 2:
00652 {
00653
00654
00655
00656
00657 auto_ptr<plConstraintNode> cNode (new plConstraintNode (t[2],"1",t[0],t[4],Comp2Int[t[1]],Comp2Int[t[3]]));
00658 exprBounds.push_back(cNode.release());
00659 }
00660 break;
00661
00662 case 1:
00663 {
00664
00665
00666
00667
00668
00669 if (IsNumber(t[0]))
00670 {
00671 auto_ptr<plConstraintNode> cNode (new plConstraintNode ("1",t[2],t[0],Comp2Int[t[1]]));
00672 exprBounds.push_back(cNode.release());
00673 }
00674 else
00675 {
00676 auto_ptr<plConstraintNode> cNode (new plConstraintNode ("1",t[0],t[2],(Comp2Int[t[1]]+2)%4));
00677 exprBounds.push_back(cNode.release());
00678 }
00679 }
00680 break;
00681
00682 case 0:
00683 {
00684
00685
00686 string tmp;
00687 istringstream sstring(str);
00688 sstring >> tmp;
00689 auto_ptr<plConstraintNode> cNode (new plConstraintNode (tmp,"1","-Inf","Inf",LOWER_THAN,LOWER_THAN));
00690 exprBounds.push_back(cNode.release());
00691 }
00692 break;
00693
00694 default:
00695
00696
00697
00698 break;
00699 }
00700 if (t)
00701 delete [] t;
00702 }
00703
00707 void FichierLP::ParseGenerals(const string& s)
00708 {
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 if (s.length() <= 1)
00719 return;
00720
00721
00722
00723 string str;
00724 string::const_iterator iter=s.begin();
00725 for (;iter!=s.end(); ++iter)
00726 {
00727 if (*iter == ',')
00728 str.push_back(' ');
00729 else
00730 str.push_back(*iter);
00731 }
00732
00733
00734 istringstream istring(str);
00735 string tmp;
00736 while (istring >> tmp) {
00737 exprGeneral.push_back(tmp);
00738 tmp.erase();
00739 }
00740 }
00741
00742
00746 void FichierLP::ParseBinaries(const string& s)
00747 {
00748
00749
00750
00751
00752
00753 if (s.length() <= 1)
00754 return;
00755
00756
00757
00758
00759
00760
00761
00762 string str;
00763 string::const_iterator iter=s.begin();
00764 for (;iter!=s.end(); ++iter)
00765 {
00766 if (*iter == ',')
00767 str.push_back(' ');
00768 else
00769 str.push_back(*iter);
00770 }
00771
00772
00773 istringstream istring(str);
00774 string tmp;
00775 while (istring >> tmp) {
00776 exprBinary.push_back(tmp);
00777 tmp.erase();
00778 }
00779 }
00780
00781
00782
00787 bool FichierLP::Open(const string& nomFile)
00788 {
00789 ifstream ifile(nomFile.c_str());
00790
00791 string s,tempInlineString;
00792 multimap<string,unsigned>::iterator k;
00793 unsigned oldK=42;
00794 bool continu=false,f=false;
00795 bool objectiveInline = false;
00796
00797
00798 if (!ifile.is_open())
00799 return false;
00800
00801
00802
00803
00804
00805
00806
00807
00808 while (getline(ifile,s,'\n'))
00809 {
00810 if (!s.empty() && IsComment(s) == false)
00811 {
00812 string::size_type position = s.rfind('\r');
00813 if (position != string::npos)
00814 s.replace(position,1," ");
00815
00817
00818 if (objectiveInline)
00819 {
00820 objectiveInline = false;
00821
00822 ParseObjective(tempInlineString);
00823 }
00824
00825
00826 string c;
00827 for (string::const_iterator iter = s.begin(); iter!=s.end();++iter)
00828 {
00829 if (*iter == ' ')
00830 break;
00831 c.push_back(*iter);
00832 }
00833
00834 transform (c.begin(),c.end(),c.begin(),::tolower);
00835
00836
00837 k = mmap.find(trim(c));
00838 if (k == mmap.end())
00839 continu = true;
00840 else
00841 continu = false,
00842 oldK = 42;
00843
00844 if (!continu && k->second == END)
00845 {
00846
00847
00848
00849
00850
00851
00852
00853
00854 return true;
00855 }
00856
00857 if (oldK==42 && objectiveInline==false && ((k->second == MAXIMIZE && oldK != MAXIMIZE) || (k->second == MINIMIZE && oldK != MINIMIZE)))
00858 {
00859 objectiveInline = true;
00860 tempInlineString = s.substr(8,s.length());
00861 }
00862
00863 switch(oldK)
00864 {
00865
00866
00867
00868
00869
00870
00871
00872 case MINIMIZE:
00873 case MAXIMIZE:
00874 {
00875 if (f==false){
00876 if (oldK==MINIMIZE) isMax=false, f=true;
00877 else isMax=true, f=true;
00878 }
00879
00880 size_t pos;
00881 string _nom="(null)";
00882
00883 s = AvoidSpaces(s);
00884
00885 if ((pos = s.find(':',0)) != string::npos)
00886 {
00887 _nom = s.substr(0,pos);
00888 nom = _nom;
00889 s.erase(0,pos+1);
00890 }
00891 ParseObjective(s);
00892 break;
00893 }
00894 case SUBJECT:
00895 {
00896 size_t pos;
00897 string nom;
00898
00899 s = AvoidSpaces(s);
00900 if ((pos = s.find(':',0)) != string::npos) {
00901 nom = s.substr(0,pos);
00902 s.erase(0,pos+1);
00903 }
00904 ParseSubjects(s,nom);
00905 break;
00906 }
00907 case BOUNDS:
00908 ParseBounds(trim(s));
00909 break;
00910 case GENERALS:
00911 ParseGenerals(trim(s));
00912 break;
00913 case BINARIES:
00914 ParseBinaries(trim(s));
00915 break;
00916 case END:
00917 break;
00918 default:
00919 break;
00920 }
00921
00922 if (continu == false)
00923 oldK = k->second;
00924 }
00925 }
00926
00927 return true;
00928 }
00929
00930 }
00931
00932