/** * Supply chain coordination problem * OPL model for the root agent. * The root receives demand for products from customers * and agrees component delivery schedules from supplier agents. */ /** * MODEL INPUT PARAMETERS */ // Time horizon int numPeriods = ...; range horizon 1..numPeriods; // Number of product configurations int numProducts = ...; range products 1..numProducts; // Number of components int numComponents = ...; range components 1..numComponents; // Maximum number of orders to consider for each component int numOrders[components] = ...; // Bill Of Materials int bom[products,components] = ...; // The batch size of a component in a particularly delivery int batchSize[components] = ...; // Delivery cost for an order of components int deliveryCost[components] = ...; // The lead time/delivery time for a particular product // I.e. the number of periods between an order being shipped // and the order arriving at the customer int leadtime[products] = ...; // Number of processing cycles for each configuration int cycles[products]= ...; // Number of cycles required to setup a configuration int setupCycles[products] = ...; // Factory capacity int capacity[horizon] = ...; // Demand for products int demand[horizon,products] = ...; // Cost for not meeting an order for product i int penaltyCost[products] = ...; // Starting product inventory int openingProductInventory[products] = ...; // Starting component inventory int openingComponentInventory[components] = ...; // Holding costs int productHoldingCost[products] = ...; int componentHoldingCost[components] = ...; // Setup costs int setupCosts[products] = ...; // Constants int maxManufacture = max(t in horizon) capacity[t]; int maxDelivery = max(t in horizon, p in products) demand[t,p]; int maxOrders = max(c in components) maxNumOrders[c]; /** * PUBLIC VARIABLES * (variables constrained with other agents) */ // The number of orders for a each component to be delivered in each period. var int componentDeliverySchedule[components,horizon] in 0..maxOrders; /** * PRIVATE VARIABLES * (variables not constrained with other agents) */ // 0/1 variable indicating whether or not an order is made for a component in a particular period var int isorder[horizon,components] in 0..1; // 0/1 variable indicating whether or not a product will be built in a particular period var int isbuilt[horizon,products] in 0..1; // The number of a product built in a particular period var int manufacture[horizon,products] in 0..maxManufacture; /** * AUXILIARY VARIABLES * (additional variables used to simplify the model specification) */ // Expected inventory arriving for each component in the time horizon var float+ componentArrivals[horizon,components]; // Remaining product inventory after each period var float+ productInventory[0..numPeriods,products]; // Remaining component inventory after each period var float+ componentInventory[0..numPeriods,components]; // The quantity of product delivered in each period var int deliveryQuantity[horizon, products] in 0..maxDelivery; // Components needed on a particular day to produce all products being manufactured var float+ componentsUsed[horizon, components]; minimize // Total cost sum (t in horizon, p in products) ( (productHoldingCost[p]*productInventory[t,p]) + (isbuilt[t,p]*setupCosts[p]) + ((demand[t,p]-deliveryQuantity[t,p])*penaltyCost[p]) ) + sum (t in horizon, c in components) ( (componentHoldingCost[c]*componentInventory[t,c]) + (isorder[t,c] * deliveryCost[c]) ) subject to { // Opening product inventory forall(p in products) productInventory[0,p]=openingProductInventory[p]; // Opening component inventory forall(c in components) componentInventory[0,c]=openingComponentInventory[c]; // Calculate the component arrivals forall(t in horizon, c in components) componentArrivals[t,c] = batchSize[c] * componentDeliverySchedule[c,t]; // The sum of the orders for any component should not be greater // than the maximum number of orders required forall(c in components) sum(t in horizon) componentDeliverySchedule[c,t] <= numOrders[c]; // Set the isorder variable correctly forall(t in horizon, c in components) maxNumComponentOrders[c] * isorder[t,c] >= componentDeliverySchedule[c,t]; // Set the isbuilt variable correctly // - should be 1 if any of that product is built on that day forall(t in horizon, p in products) maxManufacture * isbuilt[t,p] >= manufacture[t,p]; // We can never deliver more than there is demand for forall(p in products) forall (t in 1..numPeriods-leadtime[p]) deliveryQuantity[t,p] <= demand[t+leadtime[p],p]; forall(p in products) forall (t in [numPeriods-leadtime[p]+1..numPeriods]) deliveryQuantity[t,p] <= 0; // Capacity constraint for manufacturing decision // The factory's capacity for each day cannot be exceeded forall(t in horizon) sum(p in products) (manufacture[t,p]*cycles[p] + isbuilt[t,p]*setupCycles[p]) <= capacity[t]; // The number of components needed is calculated by multiplying manufacturing decision by BOM forall(t in horizon, c in components) componentsUsed[t,c] = sum(p in products) manufacture[t,p]*bom[p,c]; // Calculate the expected excess product inventory of each period forall(t in horizon, p in products) productInventory[t,p] = productInventory[t-1,p] + manufacture[t,p] - deliveryQuantity[t,p]; // Calculate the expected excess component inventory of each period forall(t in horizon, c in components) componentInventory[t,c] = componentInventory[t-1,c] + componentArrivals[t,c] - componentsUsed[t,c]; };