#include "..\Modelib.h"

using namespace std;

int main( int argc, char ** argv)
{
    // declaration du modele
    Model knap;

    // Init du solver
    knap.InitSolver(GLPK); //initialisation du solveur

    //Declarations des variables
    BoolVar x1(knap,"x1");
    BoolVar x2(knap,"x2");
    BoolVar x3(knap,"x3");
    BoolVar x4(knap,"x4");

    //----------------------------------------------------------
    //Creation du probleme lineaire: knapsack legerement modifie
    //----------------------------------------------------------
    knap.SetProblemName("Relaxation lagrangienne sur un probleme de sac-à-dos");
    //Fonction objectif
    knap.Maximize( 4*x1 + 5*x2 + 6*x3 + 7*x4  );

    knap.Add( 4*x1 + 5*x2 + 6*x3 + 7*x4 >= 0, "cprglpk");
    //Contrainte qui permet l'acceptation du probleme par cprglpk
    Constraint c1 = knap.Add( 2*x1 + 2*x2 + 3*x3 + 4*x4 <= 7, "c1");
    Constraint c2 = knap.Add( x1 - x2 + x3 - x4 <= 0 , "c2" );

    c1.Relax(0.0); //on relaxe la premiere contrainte
    c2.Relax(0.0); //on relaxe la deuxieme contrainte

    float step = 0.5;             //pas de deplacement
    float bestSol = knap.Solve(); //on initialise la meilleur borne avec le vecteur lambda nul
    unsigned stagne = 0;          //nombre d'etape ou l'on trouve la meme borne
    unsigned mstagne = 3;         //le nombre maximum d'etape ou on trouve la meme borne
    unsigned n = 0;               //le nombre d'iteration

    //----------------------------------------------------------
    //boucle principale
    //----------------------------------------------------------    
    cerr << "format de sortie" << endl
         << "iteration: valeurs des multiplicateurs -> solution" << endl;    
    while( step >= 1e-6 &&  n<100) //tant que le pas est superieur à  une certaine precision
    {
        float nouvSol = knap.Solve();  //On calcule la nouvelle solution
        if( nouvSol < bestSol )     //On actualise la meilleure solution
        {
            bestSol = nouvSol;
            stagne = 0;
            cerr << n  <<  ":  ";
            vector<LagrangianParam> v = knap.GetAllLagrangianParams();
            for(unsigned i = 0; i < v.size(); ++i)
                cerr << v[i].GetValue() << " ";
            cerr << " -> " << nouvSol << endl;
        }
        else //sinon on stagne
            ++stagne;

        list<LagrangianParam> listeViol;    //liste des contraintes violees
        list<LagrangianParam> listeSlack;   //liste des contraintes non saturees

        knap.GetInfluentLagrangianParam(listeViol,listeSlack); //on recupere ces listes

        list<LagrangianParam>::iterator i = listeViol.begin();
        for( ; i != listeViol.end(); ++i)   //pour chaque constrainte violee, on augmente le multiplicateur
        {
            *i += step;
        }

        if( listeSlack.size() ) //si des contraintes sont laches
        {
            list<LagrangianParam>::iterator i = listeSlack.begin();
            for( ; i != listeSlack.end(); ++i) //pour chaque constrainte lache, on diminue le multiplicateur
            {
                if( i->GetValue() - step > 0)  //on verifie si le lagrangien est bien positif
                  *i -=  step;
                else
                  *i = 0;
            }
        }

        if( stagne > mstagne) //si on stagne, on diminue le pas
        {
            step*=0.5;
            stagne = 0;
        }
        ++n;
    }
    cerr << "La meilleure borne de la solution optimale est donc: " << bestSol<< endl;
    knap.OutNumVarValues(false,cerr);
    cerr << "La valeur de la fonction objectif pour la solution trouvée est: " << knap.GetObjectif().Evalue( false ) << endl;
    knap.UnrelaxModel();
    cerr << "La solution optimale est: " << knap.Solve();
    return 1;
}

