Decision Optimization

 View Only
Expand all | Collapse all

Running OPL model for n times and exporting each feasible result per run

  • 1.  Running OPL model for n times and exporting each feasible result per run

    Posted Wed December 23, 2020 02:39 PM

    Dears,

    I would appreciate your help regarding the model below. In this model, I am using CP solver to minimise the makespan of houses construction. I simplified the model to make my questions clear. In the model, you will see that each activity in the house construction has a variable time. These times are generated using triangular distribution as seen in the pre-processing block. My question is how can I run the model n times (i.e. 50 times) and for each run, how can I export all the feasible results, for each run, to a unique excel file.

    Please find the model and data below:

    .mod:

    /*********************************************
     * OPL 12.10.0.0 Model
     * Author: S00184272
     * Creation Date: 23 Dec 2020 at 16:38:28
     *********************************************/
    using CP;
    
    {string} House_category 					= ...; // Only one house category is used in this model
    {string} ActivityTypes 					    = ...; // each house category has its own activities
    int requiredQuantities[House_category]		= ...; // number of required houses for each house category
    
    
    // This tuple is sued to define the information of "activities"
    tuple ActivityInfo {
       key string   	activity;
       int      		duration;
       int				lb_duration;
       int				ub_duration;
       {string} 		precedences;
    };
    {ActivityInfo} activities[House_category] = ...;
    
    
    // This tuple is used to combine the information of activities with house category and the required number of houses per category 
    tuple ActivityMatch {
       ActivityInfo 		activity;
       string       		House_category;  
       int          		nOrders;             
    };
    {ActivityMatch} allActivities = {<a,c,j> | c in House_category,a in activities[c], j in 1..requiredQuantities[c]};
    
    
    // created to store the randomly generated processing times
    int tringular_processing[allActivities];
    
    
    // triangular distribution generation block
    execute{ 
    for (var rand_time in allActivities) {
      {
    		for (var i = 1; i < allActivities.size; ++i) 
    			{
    			    var rnd = IloOplCallJava("java.util.Random", "<init>", "()");
    		  		t = rnd.nextDouble();
    		  		var a=rand_time.activity.lb_duration;
    		  		var c=rand_time.activity.duration;
    		  		var b=rand_time.activity.ub_duration;
    		  		if (t< ((c-a)/(b-a))) 	{
    		  		  					t=a+Math.round((Math.sqrt((b-a)*(c-a)*t)));
        							} 
        			else 			{
               							t=b-Math.round((Math.sqrt((b-a)*(b-c)*(1 - t))));
       								}
    				tringular_processing[rand_time]=t;
      			}
       }  
     } 
    }
    
     
    // This tuple is used to combine the allActivities with the randomly generated processing times from the triangular distribution 
    tuple combined{
      ActivityMatch 	    allActivities;
      int					trig_process;
      }
    {combined} allActivities_tri={<a,c> | a in allActivities,c in 0..tringular_processing[a]:c==maxl (tringular_processing[a]) && c>=0 };
    
    
    // used to define the precedence relations
    {combined} precedences[a in allActivities_tri] = { b | b in allActivities_tri : 
                                     a.allActivities.House_category == b.allActivities.House_category &&
                                     a.allActivities.nOrders == b.allActivities.nOrders && 
                                     b.allActivities.activity.activity  in a.allActivities.activity.precedences }; 
                                     
                                     
    // This tuple is used to enable using the if condition in dvar interval activity as seen below
    tuple combined_2{
        string House_category ;  
        int requiredQuantities; 
    };		 
    {combined_2} allActivities_2 = {<c,j> | c in House_category, j in 1..requiredQuantities[c]};	
    
    
    // the decision variable that represents the activities for each house			
    dvar interval activity[a in allActivities_tri][b in allActivities_2] size (a.allActivities.House_category ==b.House_category && a.allActivities.nOrders==b.requiredQuantities)?
    (a.trig_process):0;
    
    
    
    execute {
    
    		settings.bigmapthreshold = 50000;
    		cp.param.FailLimit = 5000;
    
    }
    
    
    // objective function
    minimize sum(a in allActivities_tri, b in allActivities_2) endOf(activity[a][b]);
    
    
    //constraints
    subject to {
     	Precedence_all:
     	forall (a in allActivities_tri, b in allActivities_2, p in precedences[a]:
           		a.allActivities.House_category==b.House_category  &&  a.allActivities.nOrders==b.requiredQuantities) 
                endAtStart(activity[p][b],activity[a][b]);
                  }              		

    .dat

    /*********************************************
     * OPL 12.10.0.0 Data
     * Author: S00184272
     * Creation Date: 23 Dec 2020 at 16:38:38
     *********************************************/
    ActivityTypes =	{ 
       activity_A,
       activity_B,
       activity_C,
       activity_D,
       activity_E	};
    
    House_category= {House_1};
    
    requiredQuantities = [5];
     
     activities = #[
       House_1:
    	{ 	<activity_A, 				10,		5,		15,		 			{}>,
    	  	<activity_B, 				30,		20,		40, 		 		{activity_A}>,   
    	  	<activity_C, 				38,		27,		87, 		 		{activity_B}>, 
    	  	<activity_D, 				32,		12,		54, 		 		{activity_C}>,
    	  	<activity_E, 				25,		10,		30, 				{activity_D}>}  ,
    	  ]#;​


    ------------------------------
    Mohamed Awad
    ------------------------------

    #DecisionOptimization


  • 2.  RE: Running OPL model for n times and exporting each feasible result per run

    Posted Thu December 24, 2020 07:47 AM

    Hello Mohamed,

    I've added to your .mod (MyCPModel) an iteration number (IterNum) and a output set that captures the iteration number, the start of the activity and the end of the activity (you can customized the output at your convenience). I have also created a control flow (flow_control.mod) in which I created a function that solve a CP instance for each iteration. In the main, a csv file is created that will save the output of each iteration. You just need to change the path, customize your output and rerun it. It works for me. I hope this helps. Let me know if you have any issues copying the file to your IDE. I can email them to you. Please confirm if it works. Cheers!

    //This is your modified MyCPModel.mod


    /********************************************* * OPL 12.10.0.0 Model
    * Author: S00184272 * Creation Date: 23 Dec 2020 at 16:38:28
    * Modified on Dec 24 2020 by 007
    *********************************************/
    using CP; {string} House_category = ...; // Only one house category is used in this model
    {string} ActivityTypes = ...;
    // each house category has its own activities
    int IterNum=...;
    int requiredQuantities[House_category] = ...;
    // number of required houses for each house category
    // This tuple is sued to define the information of "activities"
    tuple ActivityInfo
    {
    key string activity;
    int duration;
    int lb_duration;
    int ub_duration;
    {string} precedences;
    };
    {ActivityInfo} activities[House_category] = ...;
    // This tuple is used to combine the information of activities with house category and the required number of houses per category
    tuple ActivityMatch
    {
    ActivityInfo activity;
    string House_category;
    int nOrders; };
    {ActivityMatch} allActivities = {<a,c,j> | c in House_category,a in activities[c], j in 1..requiredQuantities[c]};
    // created to store the randomly generated processing times
    int tringular_processing[allActivities];
    // triangular distribution generation block
    execute
    {
    for (var rand_time in allActivities)
    {
    { for (var i = 1; i < allActivities.size; ++i) {
     var rnd = IloOplCallJava("java.util.Random", "<init>", "()"); t = rnd.nextDouble();
     var a=rand_time.activity.lb_duration;
     var c=rand_time.activity.duration;
     var b=rand_time.activity.ub_duration;
     if (t< ((c-a)/(b-a)))
     { t=a+Math.round((Math.sqrt((b-a)*(c-a)*t))); }
     else { t=b-Math.round((Math.sqrt((b-a)*(b-c)*(1 - t))));
     }
     tringular_processing[rand_time]=t;
     }
     }
     }
     }
     // This tuple is used to combine the allActivities with the randomly generated processing times from the triangular distribution
     tuple combined{ ActivityMatch allActivities; int trig_process; }
     {combined} allActivities_tri={<a,c> | a in allActivities,c in 0..tringular_processing[a]:c==maxl (tringular_processing[a]) && c>=0 }; // used to define the precedence relations
     
     {combined} precedences[a in allActivities_tri] =
     { b | b in allActivities_tri : a.allActivities.House_category == b.allActivities.House_category
     && a.allActivities.nOrders == b.allActivities.nOrders && b.allActivities.activity.activity in a.allActivities.activity.precedences};
     
     // This tuple is used to enable using the if condition in dvar interval activity as seen below
     tuple combined_2{ string House_category ; int requiredQuantities; }; {combined_2} allActivities_2 = {<c,j> | c in House_category, j in 1..requiredQuantities[c]};
     // the decision variable that represents the activities for each house
     dvar interval activity[a in allActivities_tri][b in allActivities_2] size (a.allActivities.House_category ==b.House_category && a.allActivities.nOrders==b.requiredQuantities)? (a.trig_process):0;
     
     execute
     {
     settings.bigmapthreshold = 50000;
     cp.param.FailLimit = 5000;
     }
     // objective function
     minimize sum(a in allActivities_tri, b in allActivities_2) endOf(activity[a][b]);
     //constraints
     subject to
     {
     Precedence_all: forall (a in allActivities_tri, b in allActivities_2, p in precedences[a]: a.allActivities.House_category==b.House_category && a.allActivities.nOrders==b.requiredQuantities)
     endAtStart(activity[p][b],activity[a][b]);
     }
     
     tuple tup_out
     {
     int IterNum;
     int StartOfActivity;
     int EndOfActivity;
     }
     
     {tup_out} Set_out={<IterNum,startOf(activity[a][b]),endOf(activity[a][b])>| a in allActivities_tri, b in allActivities_2};
    //This is the flow control 

     /*********************************************
     * OPL 12.6.3.0 Model
     * Author: 007
     * Creation Date: 2020-12-16 at 10:24:18 AM
     *********************************************/
     
     int IterationNum=10;
     {int} Set=asSet(1..IterationNum);
     
     
    main{
    var DIR="C:\\Users\\nourredine.hail\\Desktop\\CPLEXModels\\Test\\"
    var csvFileName="MyCPModel.csv";
    var ofile=new IloOplOutputFile(DIR+csvFileName);
    //var ofile = new IloOplOutputFile("C:\\Users\\nourredine.hail\\Desktop\\CPLEXModels\\Test\\Test.csv");
    //Create the Column names
    ofile.writeln( 
    "IterNum",",","StartOfActivity",",","EndOfActivity"); 
    //Function that solves a CP instance
    function SolveOPL_CPModel(IterNum)
     { 
      var MyCPModel_source = new IloOplModelSource("MyCPModel.mod");
      var MyCPModel_cplex = new IloCP();
      var MyCPModel_def = new IloOplModelDefinition(MyCPModel_source);
      var MyCPModel_opl = new IloOplModel(MyCPModel_def,MyCPModel_cplex);
      var MyCPModel_data = new IloOplDataSource("MyCPModel.dat"); 
      var MyCPModel_dataelts= new IloOplDataElements();
      MyCPModel_opl.settings.mainEndEnabled=true; 
      MyCPModel_opl.settings.warnings=false;
      //Add the iteration number
      MyCPModel_dataelts.IterNum=IterNum;
      
      MyCPModel_opl.addDataSource(MyCPModel_dataelts);
      MyCPModel_opl.addDataSource(MyCPModel_data);
      MyCPModel_opl.generate();  
      if(MyCPModel_cplex.solve()) MyCPModel_opl.postProcess();
      //write the output into the cvs file
      for(var a in MyCPModel_opl.Set_out)
      ofile.writeln(a.IterNum,",",a.StartOfActivity,",",a.EndOfActivity)
      //End the opl instance to free memory
      MyCPModel_opl.end();
        }
       
        for(var IterNum in thisOplModel.Set)   SolveOPL_CPModel(IterNum)
        ofile.close();
     }
       
       



    ------------------------------
    Nourredine Hail
    ------------------------------



  • 3.  RE: Running OPL model for n times and exporting each feasible result per run

    Posted Sat December 26, 2020 09:03 AM

    Dear Nourredine,

    Thanks a million for your kind reply. I made few modifications to match my original case and your solution is perfect.

    I have another question, whenever I run the model, which is a large model, with IterationNum =100 for example, the OPL stops working after it reaches a certain iteration number (i.e. 30). Is there a way to check why the OPL stops working in that case? 

    Thanks again,



    ------------------------------
    Mohamed Awad
    ------------------------------



  • 4.  RE: Running OPL model for n times and exporting each feasible result per run

    Posted Mon December 28, 2020 07:15 AM

    Hi Mohamed,

    I just have encountered the same issue when I tried to run the flow control for 100 iterations. I am not sure what it is causing it but I believe it is the way the data is created, I mean the randomness of the data and the triangular distribution.

    I ran the model for 50 iterations and it worked. I saved the data under a first csv file. I changed the name the csv file and rerun the model for 50 iterations a  2nd time and it worked again. Since the data is random, the likelihood that the data of 1st run = data of the 2nd run is close to 0!  I even run it a 3rd time (50 iterations) and 4 time (50 iterations) and it went well as well . 

    At this time, I am not sure why the randomness of the data creates an issue.Perhaps our IBM-ers can provide more insights to your problem.

    See attachment for the results that prove my point :-)

    Best regards,

    PS: I am not an expert in OPL, I just have some practical experience.



    ------------------------------
    Nourredine Hail
    ------------------------------