Decision Optimization

 View Only
  • 1.  IloFunction

    Posted Mon December 27, 2021 04:31 PM

    Hello

    I am trying to find an example using the IloFunction but I can't find anything clear enough for me in the documentation. I found the following  Decision Optimization post but I cannot find the example "in the user manual at section "Advanced Modeling with Set Variables".

    My original problem is the following: I have a two dimensional integer var array of 0,1,2 and another two dimensional var array with integer. What I need is to be able to count a specific number between two consecutives 1/2. Example of single row:
    000010000000020000001000000001 (the position/index of the 0,1,2 could change)
    000006666000600007700770000000 (the position of the numbers could change)

    Between the first 1 to 2 the number of 6s is 5. The idea is to build a constraint that limit the number of 6s between two consecutives 1 or 2 to whatever I need.


    Hope it's clear
    Regards



    ------------------------------
    javier rodrigo
    ------------------------------


  • 2.  RE: IloFunction

    Posted Tue December 28, 2021 01:29 PM
    Hello Javier,
    IloFunction was in ILOG Solver API which isn't available any more
    How would you have liked to use it?
    Regards,


    ------------------------------
    Christiane Bracchi
    ------------------------------



  • 3.  RE: IloFunction
    Best Answer

    Posted Wed December 29, 2021 09:33 AM
    Hi,

    you could also count in your constraints.

    For instance with OPL you could write

    range r=1..30;
    
    int xval[r]=[0,0,0,0,1,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1 ];
    int max6=3;
    
    dvar int x[r] in 0..2;
    dvar int+ y[r] in 0..10;
    dvar int+ nb6[r] in 0..max6;
    
    maximize sum(i in r) (y[i]==6);
    
    subject to
    {
      forall(i in r) x[i]==xval[i];
      forall(i in r) (x[i]!=0)=>(nb6[i]==0);
      forall(i in r) (x[i]!=0)=>(y[i]!=6);
      
      forall(i in r:i!=1) (x[i]==0) => (nb6[i]==nb6[i-1]+(y[i]==6));
    }​

    which gives

    y = [6 6 6 6 0 6 6 5 5 5 5 6 5 0 6 6 0 0 0 6 0 6 6 6 0 0 0 0 0 0];
    x = [0 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1];
    nb6 = [0 1 2 3 0 1 2 2 2 2 2 3 3 0 1 2 2 2 2 3 0 1 2 3 3 3 3 3 3 0];


    I wrote that in OPL but you can do the same with all APIs and with MIP and CPOptimizer



    ------------------------------
    [Alex] [Fleischer]
    [EMEA CPLEX Optimization Technical Sales]
    [IBM]
    ------------------------------



  • 4.  RE: IloFunction

    Posted Sun January 02, 2022 03:22 AM
    Nice!! It's working good with your idea. Thanks a lot

    ------------------------------
    javier rodrigo
    ------------------------------



  • 5.  RE: IloFunction

    Posted Mon January 03, 2022 02:47 PM
    I am trying to improve the model. I coded your suggestion like this:
            IloArray<IloIntVarArray> numTAs(env, simu.plantilla.size());
            IloArray<IloIntVarArray> numTAs2(env, simu.plantilla.size());
            for (i = 0; i < simu.plantilla.size(); i++) {
                numTAs[i] = IloIntVarArray(env, simu.numDiasTurnero+1, 0, 6); //valores entre 0 y 6 como máximo de turnos aeronáuticos por ciclo
                numTAs2[i] = IloIntVarArray(env, simu.numDiasTurnero+1, -1, 5); //valores entre -1 y 5 como máximo de turnos aeronáuticos por ciclo, así se prohiben 6 TAs con descanso de 48h
                model.add(numTAs[i][simu.numDiasTurnero] == 0); //inicializa numTAs(ultimodia) a 0 
                model.add(numTAs2[i][simu.numDiasTurnero] == -1); //inicializa numTAs2(ultimodia) a -1 asuminedo descanso de 54h en último día
                for (d = simu.numDiasTurnero-1; d >=0; d--) {
                    numTAs[i][d] = IloIntVar(env, 0, 6);
                    numTAs2[i][d] = IloIntVar(env, -1, 5);
                    model.add(IloIfThen(env, Ciclos[i][d] != 0, numTAs[i][d] == 0));
                    model.add(IloIfThen(env, Ciclos[i][d] == 0, numTAs[i][d] == numTAs[i][d + 1] + (TurneroCalculado[i][d] != l && TurneroCalculado[i][d] != o)));
                    model.add(IloIfThen(env, Ciclos[i][d] != 0, numTAs2[i][d] == -Ciclos[i][d] + 1)); //inicializa numTAs2 = -1 los ciclos con 54h de descanso y a 0 los de 48h. Así los ciclos que tengas 6 TAs con descanso de 54h, su suma dará 5TAs pero los de 48h darán 6TAs
                    model.add(IloIfThen(env, Ciclos[i][d] == 0, numTAs2[i][d] == numTAs2[i][d + 1] + (TurneroCalculado[i][d] != l && TurneroCalculado[i][d] != o)));
                }
            }​
    however, it is taking very long (taking from 3875 variables to 5859 and 9841 constraits to 13747)

    In OPL I implemented this one that takes less time
    	forall (i in Plantilla, d in 0..NumDiasTurnero-2, d1 in d+1..NumDiasTurnero-1)
    		(Ciclos[i][d] * Ciclos[i][d1] > 0 && (sum(dx in d+1..d1) (Ciclos[i][dx] > 0))==1 => 
    		(sum(dx2 in d+1..d1, t in tipoDeTurno : t.Tipo != "l") TurneroCalculado[i][dx2][t]) <= 6 && //número de turnos aeronáuticos consecutivos <=6
    		(sum(dx2 in d+1..d1, t in tipoDeTurno : t.Tipo == "m" || t.Tipo == "m1" || t.Tipo == "im") TurneroCalculado[i][dx2][t]) <= 5 && //número de mañanas (m, m1, im) seguidas <=5
    		(sum(dx2 in d+1..d1, t in tipoDeTurno : t.Tipo == "im" || t.Tipo == "it" || t.Tipo == "ino") TurneroCalculado[i][dx2][t]) <= 2 ); //máximo de dos imaginarias por ciclo
    
    	forall (i in Plantilla, d in 0..NumDiasTurnero-2, d1 in d+1..NumDiasTurnero-1)
    		((Ciclos[i][d] * Ciclos[i][d1] > 0 && (sum(dx in d+1..d1) (Ciclos[i][dx] > 0))==1 && 
    		(sum(dx2 in d+1..d1, t in tipoDeTurno : t.Tipo != "l" && t.Tipo != "o") TurneroCalculado[i][dx2][t]) == 6) => Ciclos[i][d1] == 2); //después de 6 días aeronáuticos, descanso >= 54h
    ​
    but I don´t know how to translate it into C++ API. The sum(...) is giving me headaches.

    I worked it out as well using minizing running cplex as solver and it is much faster (I don´t know why). This part of the code in minizic is like this:
    constraint forall (i in Plantilla, d in 0..NumDiasTurnero-2 where Ciclos[i,d] != 0)
                (let {var int: d1 = min([dx | dx in d+1..NumDiasTurnero-1 where Ciclos[i,dx] != 0 ]++[NumDiasTurnero]),
                      var int: turnosAeronauticos = sum([1 | dx2 in d+1..d1 where TurneroCalculado[i,dx2,l] == 0 /\ TurneroCalculado[i,dx2,o] == 0])} in (
                ((d1 >= d+7) -> (turnosAeronauticos <= 6)) /\ %número de turnos aeronáuticos consecutivos <=6
                ((d1 >= d+6) -> (sum([1 | dx2 in d+1..d1 where TurneroCalculado[i,dx2,m] == 1 \/ TurneroCalculado[i,dx2,m1] == 1 \/ TurneroCalculado[i,dx2,im] == 1]) <= 5)) /\ %número de mañanas (m, m1) seguidas <=5
                ((d1 >= d+7 /\ turnosAeronauticos == 6 -> Ciclos[i,d1] == 2)) /\ %después de 6 días aeronáuticos, descanso >= 54h
                (sum([1 | dx2 in d+1..d1 where TurneroCalculado[i,dx2,im] == 1 \/ TurneroCalculado[i,dx2,it] == 1 \/ TurneroCalculado[i,dx2,ino] == 1]) <=2) %máximo de dos imaginarias por ciclo
                ));​

    Because in minizinc you can define local variables (d1 and turnosAeronauticos) that are used below several times, it might save time.

    Thanks



    ------------------------------
    javier rodrigo
    ------------------------------



  • 6.  RE: IloFunction

    Posted Tue March 15, 2022 11:28 AM
    Thanks working great.

    ------------------------------
    Ricky Martin
    ------------------------------



  • 7.  RE: IloFunction

    Posted Sun January 02, 2022 03:21 AM
    In minizinc I was able to construct a function for this matter, so I was just looking around for a way...

    ------------------------------
    javier rodrigo
    ------------------------------