Decision Optimization

Decision Optimization

Delivers prescriptive analytics capabilities and decision intelligence to improve decision-making.

 View Only
  • 1.  heightAtEnd

    Posted Mon April 27, 2020 10:29 AM

    This place looks nicer than old one ^^ I have been a big beneficiary of this forum.

    I feel very lucky to learn CPO. I see huge publication opportunities as a researcher and huge real-world implementation opportunities as a practitioner. Currently, I am working with semiconductor & display industries to introduce CPO. It has been very difficult due to the bad experience with CPO about 20 years ago in that particular companies ^^. They don't know how much CPO has been improved. I think the door will be soon open because of CPO's own merits.

    This is the continuation of https://www.ibm.com/developerworks/community/forums/html/forum?id=11111111-0000-0000-0000-000000002067&ps=25

    I think we are getting close to the solution.
    The revised code generates a following tour.
    Depot=>S1=>65=>98=>S1=>20=>24=>57=>S15=>Depot (Where S refers the charging station).
    The truck recharges (12 units) at S1 immediately after departing from the depot. The truck starts with a full battery level of 78 units. Since both the depot and S1 are located at the same cords. This recharging is not valid.
    The code seems to using this invalid charging to give the truck enough energy until the next charging. Note the distance S1=>65=>98=>S1 is equal to 90 (12+78).
    The code seems to allow the battery go beyond the maximum level of 78.

    Thanks,
    Andy



    ------------------------------
    Andy Ham
    ------------------------------

    #DecisionOptimization


  • 2.  RE: heightAtEnd

    Posted Wed April 29, 2020 04:41 AM
    Hello Andy,

    yes, the truck recharges 12 units at S1 immediately after departing from the depot at time 4. However it already discharged 13 units at time 0. This discharge was caused by stepAtStart for the S1. The value 13 was computed by:
     dischargeValues[j][t] == - dNtoN[j.id][typeOfNext(seqTrk[t], itvJ2T[j][t], j.id, j.id)];
    I'm wondering whether instead of typeOfNext there shouldn't be typeOfPrev?
    I added into postprocessing display of the events (charges and discharges) for each truck. Here is the result:
    Truck 1 events: 
      (Battery starts charged with level 78.)
      Time 0 at S01 discharging -13
      Time 4 at S01 charging +12
      Time 67 at C65 discharging -36
      Time 157 at C65 (no change)
      Time 193 at C98 discharging -31
      Time 283 at C98 (no change)
      Time 314 at S01 discharging -10
      Time 340 at S01 charging +78
      Time 350 at C20 discharging -5
      Time 440 at C20 (no change)
      Time 445 at C24 discharging -38
      Time 535 at C24 (no change)
      Time 989 at C57 discharging -11
      Time 1079 at C57 (no change)
      Time 1090 at S151 (no change)
      Time 1116 at S151 discharging -24
      Time 1116 at S151 (no change)
      Time 1116 at S151 charging +78
      Time 1140 at DN (no change)
      Time 1140 at DN (no change)
    I attach the modified model file.
    Regards, Petr

    ------------------------------
    Petr Vilím
    IBM
    ------------------------------



  • 3.  RE: heightAtEnd

    Posted Wed April 29, 2020 08:40 AM

    After changing to typeOfPrev as you suggested, the work-around code seems working! Owing to the postscript, I was able to confirm the model. 

    dischargeValues[j][t] == - dNtoN[j.id][typeOfPrev(seqTrk[t], itvJ2T[j][t], j.id, j.id)]; 

    Only concern is the speed. This work-around could not find the optimal after 10 mins run-time, compared to immediate results from MIP. I guess I need to wait the next release of CPO that addresses the cumulative function issue.

    name type start end size dist charge discharge Battery
    itvJ2T[<1001,"D0","d",40,50,0,0,1236,0>][1] 1001 52 52 0 78
    itvJ2T[<7,"C65","c",48,40,10,67,139,90>][1] 7 67 157 90 13 0 -13 65
    itvJ2T[<1,"S01","f",40,50,0,0,1236,0>][1] 1 170 174 4 13 12 -13 64
    itvJ2T[<6,"C98","c",58,75,20,0,1115,90>][1] 6 205 295 90 31 0 -31 33
    itvJ2T[<2,"S01","f",40,50,0,0,1236,0>][1] 2 359 375 16 31 48 -31 50
    itvJ2T[<5,"C20","c",30,50,10,0,1136,90>][1] 5 385 475 90 10 0 -10 40
    itvJ2T[<9,"C24","c",25,50,10,0,1131,90>][1] 9 480 570 90 5 0 -5 35
    itvJ2T[<4,"S151","f",39,26,0,0,1236,0>][1] 4 642 644 2 28 6 -28 13
    itvJ2T[<3,"S151","f",39,26,0,0,1236,0>][1] 3 766 777 11 0 33 0 46
    itvJ2T[<8,"C57","c",40,15,40,989,1063,90>][1] 8 989 1079 90 11 0 -11 35
    itvJ2T[<2001,"DN","r",40,50,0,0,1236,0>][1] 2001 1114 1114 0 35 0 -35 0
    177

    Thanks for all your help.

    Andy



    ------------------------------
    Andy Ham
    ------------------------------



  • 4.  RE: heightAtEnd

    Posted Wed April 29, 2020 10:56 AM
    For me it finds the optimal solution (objective 176). Note that there are two typeOfNext in the model, it is necessary to change both.

    Regarding the workaround and the bug. The bug in version 12.10 is only in computation of cumulative function in OPL that happens after the solve. The bug is not in the engine. I.e. engine computes the solution correctly, and due to the bug OPL is not able to display it. The workaround is to introduce integer variables that store the changes of the cumulative function so that the cumulative function can be computed manually after the solve. That's what the script at the end of the model file does.

    In other words, the bug in OPL does not influence is not the reason why it is not easy for the engine to find the solution and prove its optimality. I'm afraid that it is not a good problem for CP Optimizer because some important propagation are missing (at least in version 12.10).

    I attach one more version of the model. I introduced variables "predecessor". They does not seem to be very useful in the model, but by having them explicitly, the search my start to work on them instead of working on time. I also added a redundant constraint and a search phase. This way we have a proof now. However this is just a toy problem and I'm afraid it will not work very well on real problems.

    Regards, Petr

    ------------------------------
    Petr Vilím
    IBM
    ------------------------------



  • 5.  RE: heightAtEnd

    Posted Thu April 30, 2020 09:26 AM

    Your model works great! Thanks! Although you mentioned that it is not a good problem for CPO, the code still beats MIP and combined model of MIP/CP  for VRP+ time-of-use pricing problem in most of benchmark instances.

    This paper addresses an electrical vehicle routing problem with time window (E-VRPTW) under time-of-use (TOU) pricing aiming to minimize the electricity-cost as well as the number of used vehicles and total travel distance. In particular, the proposed solution cleverly shifts battery charging to off-peak periods and adjusts the charging duration to reduce the cost. First, the problem is carefully carved in a mixed integer linear programming model. Second, a constraint programming model is built. Third, a combined model is constructed to exploit the strengths of both models. The computational study demonstrates we can reduce the electricity-cost by ??% on average while not compromising other objectives.

    I am sorry but I have one more favor. The benchmark instances have float values for battery capacity and refueling rate. When I solve the problems with simple ftoi conversion, it worked well. However, when I tried to consider the exact values with scaling factor, the battery restriction does not work any more, as you can see in below. There must be my errors, but I could not find them ^^

    Truck 2 cumBattery levels:
    From time 0 value 7775
    From time 67 value 6475
    From time 193 value 2875
    From time 321 value -925
    From time 416 value -1425
    From time 989 value -5225
    From time 1090 value -6325
    From time 1114 value -8725

    int Q=ftoi(ceil(QQ*scale)); //77.5; // Vehicle fuel tank capacity
    int g=ftoi(ceil(gg*scale));//  3.47; //inverse refueling rate

     //Battery consumption 
    dischargeValues[j][t] == - scale*dNtoN[j.id][predecessor[t][j]]; 
    dischargeValues[j][t] ==  scale*dischargeExprs[j][t]; 

    //Battery charging 
    forall(j in aJobs,t in Trucks: j.t=="f")      chargeValues[j][t] == g*sizeOf(itvJ2T[j][t]);
    forall(j in aJobs,t in Trucks)                   chargeValues[j][t] == scale*chargeExprs[j][t];



    ------------------------------
    Andy Ham
    ------------------------------



  • 6.  RE: heightAtEnd

    Posted Thu April 30, 2020 02:17 PM
    Hello Andy,

    I think I found it. Here is the modified model. I changed also the script at the end a little. And I changed value of FailureDirectedSearchEmphasis from 1 to 0.99. If you look for proof and you want to use multiple cores then you can also experiment with values such as 1.99, 2.99 etc.

    Petr

    ------------------------------
    Petr Vilím
    IBM
    ------------------------------



  • 7.  RE: heightAtEnd

    Posted Fri May 01, 2020 10:11 AM

    Hi Petr,

    I don't know how to appreciate your help enough. Thanks a lot! It works beautifully. Initially, I could not understand the difference between the bug in OPL and Engine, although you explained it multiple times. Thanks for your patience. I think I am getting old ^^.

    The enclosed is the final version for E-VRP with time-of-use electricity pricing. In general, an MIP for homogeneous VRP is strong since the well-known formulation does not explicitly employ a vehicle index, but it successfully determines the number of used vehicles. However, MIP turned out to be inefficient for E-VRP with time-of-use electricity pricing due to large number of binary variables to calculate the electricity cost.

    Thanks agian,
    Andy



    ------------------------------
    Andy Ham
    ------------------------------