Decision Optimization

 View Only
  • 1.  tuple slicing in OPL

    Posted Wed July 08, 2020 08:52 AM
    Hello,
    I am very new to OPL, and am working on an optimization problem where online orders need to be routed to stores for fulfillment. Below .mod file (OPL) will help you in understanding the structure of data. I appreciate any help with this, it will encourage me to use OPL further.Thank you.
    tuple orderData {
       string	orderId;
       string	sku;
       int		zipCode;
       int		units;	  
    }
     
    {orderData} Orders = ...;
     
    tuple storeInvData {
       string	storeId;
       int		zipCode;
       string 	sku;
       int		inventory;
    }
     
    {storeInvData} Stores = ...;
     
     
    tuple transpCost {
       int		zipcode1;
       int		zipcode2;
       int		cost;
    }
    
    {transpCost} Cost = ...;
    
    tuple orderSku {
       string	orderId;
       string	sku;
    }
     
    {string} orderids = {i.orderId | i in Orders};
    {string} storeids = {i.storeId | i in Stores};
    {orderSku} ordersku = {<i,j> | <i,j,k,l> in Orders};
    
    
    dvar boolean Order_Sku_Store[ordersku][storeids];
    dvar boolean Order_Store[orderids][storeids];
    
    // BELOW is where I am getting stuck at :
    
    //i need to loop through each order, store combination, fetch corresponding 
    //zipcodes (pair of zipcodes) and then look up this pair in the set of tuples - 'Cost'
    //defined above to get the cost indexed by [orderids][storeids]. Then to minimize total //cost, I want to create an 
    //expression where I multiply 'Order_Store' decision variables with corresponding 
    //cost derived from above
    
    //below is what i have tried, but i am getting an error. I need to calculate cost 
    //index by orderids, storeids
    
    int cst[orderids][storeids];
    
    tuple zips {
       int	zipCode1;
       int	zipCode2;
    }
    
    execute {
      for (var m in orderids)
      	for (var n in storeids) {
      	  {zips} y = {<i.zipCode, j.zipCode> | i in Orders, j in Stores : i.orderId == m && j.storeId == n}; // ERROR : script parsing error : missing expression
      	  cst[m, n] = [i.cost | i in Cost : <i.zipcode1, i.zipcode2> in y];
      	} 	
    }


    ------------------------------
    Bhartendu Awasthi
    ------------------------------

    #DecisionOptimization


  • 2.  RE: tuple slicing in OPL

    Posted Wed July 08, 2020 10:11 AM
    Hi,

    you re mixing OPL language and OPL scripting.

    tuple orderData {
       string	orderId;
       string	sku;
       int		zipCode;
       int		units;	  
    }
     
    {orderData} Orders = {<"A","P",1,2>,<"B","A",3,4>};
     
    tuple storeInvData {
       string	storeId;
       int		zipCode;
       string 	sku;
       int		inventory;
    }
     
    {storeInvData} Stores = {<"s",1,"A",2>};;
     
     
    tuple transpCost {
       key int		zipcode1;
       key int		zipcode2;
       int		cost;
    }
    
    {transpCost} Cost = {<3,1,10>,<1,1,4>};
    
    tuple orderSku {
       string	orderId;
       string	sku;
    }
     
    {string} orderids = {i.orderId | i in Orders};
    {string} storeids = {i.storeId | i in Stores};
    {orderSku} ordersku = {<i,j> | <i,j,k,l> in Orders};
    
    
    dvar boolean Order_Sku_Store[ordersku][storeids];
    dvar boolean Order_Store[orderids][storeids];
    
    // BELOW is where I am getting stuck at :
    
    //i need to loop through each order, store combination, fetch corresponding 
    //zipcodes (pair of zipcodes) and then look up this pair in the set of tuples - 'Cost'
    //defined above to get the cost indexed by [orderids][storeids]. Then to minimize total //cost, I want to create an 
    //expression where I multiply 'Order_Store' decision variables with corresponding 
    //cost derived from above
    
    //below is what i have tried, but i am getting an error. I need to calculate cost 
    //index by orderids, storeids
    
    //int cst[orderids][storeids];
    
    tuple zips {
       int	zipCode1;
       int	zipCode2;
    }
    
    {zips} y[m in orderids][n in storeids] = {<i.zipCode, j.zipCode> | i in Orders, j in Stores : i.orderId == m && j.storeId == n}; 
    
    int cst[m in orderids][ n in storeids] = (card(y[m][n])>=1)
    ?item(Cost,<first(y[m][n]).zipCode1,first(y[m][n]).zipCode2>).cost
    :0;
    
    execute
    {
      writeln(cst);
    }
    
    //execute {
    //  for (var m in orderids)
    //  	for (var n in storeids) {
    //  	  {zips} y = {<i.zipCode, j.zipCode> | i in Orders, j in Stores : i.orderId == m && j.storeId == n}; // ERROR : script parsing error : missing expression
    //  	  cst[m, n] = [i.cost | i in Cost : <i.zipcode1, i.zipcode2> in y];
    //  	} 	
    //}​


    works fine and gives

    [[4]
             [10]]​


    ------------------------------
    ALEX FLEISCHER
    ------------------------------



  • 3.  RE: tuple slicing in OPL

    Posted Thu July 09, 2020 12:19 AM
    Thank you very much Alex for the prompt response and sharing the code snippet. Learnt quite a few features about OPL !

    ------------------------------
    Bhartendu Awasthi
    ------------------------------



  • 4.  RE: tuple slicing in OPL

    Posted Thu July 09, 2020 12:44 AM
    Hi

    you re welcome 

    https://community.ibm.com/community/user/datascience/communities/community-home/digestviewer/viewthread?GroupId=5557&MessageKey=e1b0c4e9-9665-4cf8-b85e-2498635ecc15&CommunityKey=ab7de0fd-6f43-47a9-8261-33578a231bb7&tab=digestviewer&ReturnUrl=%2fcommunity%2fuser%2fcommunities%2fcommunity-home%2fdigestviewer%3fcommunitykey%3dab7de0fd-6f43-47a9-8261-33578a231bb7%26tab%3ddigestviewer

    could help you maybe 

    regards

    ------------------------------
    ALEX FLEISCHER
    ------------------------------



  • 5.  RE: tuple slicing in OPL

    Posted Thu July 09, 2020 03:38 AM

    Thanks Alex, while learning I am also referring to OPL language, user reference and example that CPLEX ships with its installation.

    With your help, I was able to complete the formulation of the problem in OPL (continuing with the code snippet you provided). Whenever you have some time to spare, I would be glad if you could pls. review the below formulation. I did some test, the code works fine. If you have any specific feedback, pls feel free to share. Thank you.

    tuple orderData {
       string	orderId;
       string	sku;
       int		zipCode;
       int		units;	  
    }
     
    {orderData} Orders = {<"A","P",1,2>,<"B","A",3,4>};
     
    tuple storeInvData {
       key string	storeId;
       int		zipCode;
       key string 	sku;
       int		inventory;
    }
     
    {storeInvData} Stores = {<"s",1,"A",20>,<"s",1,"P",20>,<"t",1,"P",20>,<"u",5,"A",20>};
     
     
    tuple transpCost {
       key int		zipcode1;
       key int		zipcode2;
       int		cost;
    }
    
    {transpCost} Cost = {<3,1,10>,<1,1,4>,<3,5,4>,<1,5,4>};
    
    tuple orderSku {
       string	orderId;
       string	sku;
    }
     
    {string} orderids = {i.orderId | i in Orders};
    {string} storeids = {i.storeId | i in Stores};
    {string} prods = {i.sku | i in Orders};
    
    {orderSku} ordersku = {<i,j> | <i,j,k,l> in Orders};
    
    // added the below line to store units demanded by customers
    // indexed by 'ordersku' tuple
    int units[ordersku] = [<t.orderId,t.sku>:t.units | t in Orders];
    
    tuple zips {
       int	zipCode1;
       int	zipCode2;
    }
    
    {zips} y[m in orderids][n in storeids] = {<i.zipCode, j.zipCode> | i in Orders, j in Stores : i.orderId == m && j.storeId == n}; 
    
    int cst[m in orderids][ n in storeids] = (card(y[m][n])>=1)
    ?item(Cost,<first(y[m][n]).zipCode1,first(y[m][n]).zipCode2>).cost
    :0;
    
    // leverage logic similar to above where cost (cst) has been extarcted
    tuple str_prod {
       string	str_ids;
       string	prod_ids;
    }
    
    {str_prod} z[i in storeids][j in prods] = {<st.storeId, st.sku> | st in Stores : st.storeId == i && st.sku == j};
    
    int store_inv[str in storeids][prd in prods] = (card(z[str][prd])>=1)
    ?item(Stores,first(z[str][prd])).inventory
    :0;
    
    
    dvar boolean Order_Sku_Store[ordersku][storeids];
    dvar boolean Order_Store[orderids][storeids];
    
    dexpr int TotalCost =
    	sum(i in orderids, j in storeids)
    	  Order_Store[i][j] * cst[i][j];
    	  
    minimize TotalCost;
    
    subject to {
      
      // every order (order-sku combination) should be fulfilled by only 1 store
      forall(<o,prd> in ordersku)
        ctFulfiment:
        sum(str in storeids)
          	Order_Sku_Store[<o,prd>][str] == 1;
          	
      // if a order-sku is fulfilled by a particular
      // store : Order_Sku_Store == 1 then turn Order_Store decision varb == 1	
      forall(<o,prd> in ordersku, str in storeids)
        ctX:
        (Order_Sku_Store[<o,prd>][str] == 1) => (Order_Store[o][str] == 1);   
      
      // finally ensure that store which fulfils an order should have sufficient 
      // inventory at hand
      forall(str in storeids, prd in prods)
        ctInventory:
        sum(<o,prd> in ordersku)
    		units[<o,prd>] * Order_Sku_Store[<o,prd>][str] <= store_inv[str][prd];
    		
    }


    ------------------------------
    Bhartendu Awasthi
    ------------------------------