use of milp.MipCashConstraint in project Stochastic-Inventory by RobinChen121.
the class CashConstraint method main.
// d=[8, 10, 10], iniCash=20, K=10; price=5, v=1; h = 1
public static void main(String[] args) {
double[] meanDemand = { 10 };
// double[] meanDemand = {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
double iniInventory = 0;
double iniCash = 200;
double fixOrderCost = 0;
double variCost = 2;
double[] price = { 6 };
double depositeRate = 0;
double salvageValue = 1;
double holdingCost = 0;
FindCCrieria criteria = FindCCrieria.XRELATE;
// costs like wages or rents which is required to pay in each period
double overheadCost = 0;
// rate from revenue to pay overhead wages
double overheadRate = 0;
// maximum ordering quantity when having enough cash
double maxOrderQuantity = 200;
double truncationQuantile = 0.9999;
int stepSize = 1;
double minInventoryState = 0;
double maxInventoryState = 500;
// can affect results, should be smaller than minus fixedOrderCost
double minCashState = -1000;
double maxCashState = 2000;
// large penalty cost cause big gaps for simulation results, since may generate zero demand
double penaltyCost = 0;
double discountFactor = 1;
// get demand possibilities for each period
int T = meanDemand.length;
Distribution[] distributions = IntStream.iterate(0, i -> i + 1).limit(T).mapToObj(i -> new PoissonDist(meanDemand[i])).toArray(Distribution[]::new);
// double[] values1 = {6, 7};
// double[] probs1 = {0.95, 0.05};
// double[] values2 = {6, 7};
// double[] probs2 = {0.95, 0.05};
// DiscreteDistribution[] distributions = new DiscreteDistribution[T];
// for (int i = 0; i < T; i++) {
// if (i % 2 == 0)
// distributions[i] = new DiscreteDistribution(values1, probs1, values1.length);
// else
// distributions[i] = new DiscreteDistribution(values2, probs2, values2.length);
// }
double[][][] pmf = new GetPmf(distributions, truncationQuantile, stepSize).getpmf();
// feasible actions
Function<CashState, double[]> getFeasibleAction = s -> {
double maxQ = // maxOrderQuantity;
(int) Math.min(maxOrderQuantity, Math.max(0, (s.getIniCash() - overheadCost - fixOrderCost) / variCost));
return DoubleStream.iterate(0, i -> i + stepSize).limit((int) maxQ + 1).toArray();
};
// immediate value
ImmediateValueFunction<CashState, Double, Double, Double> immediateValue = (state, action, randomDemand) -> {
int t = state.getPeriod() - 1;
double revenue = price[t] * Math.min(state.getIniInventory() + action, randomDemand);
double fixedCost = action > 0 ? fixOrderCost : 0;
double variableCost = variCost * action;
double deposite = (state.getIniCash() - fixedCost - variableCost) * (1 + depositeRate);
double inventoryLevel = state.getIniInventory() + action - randomDemand;
double holdCosts = holdingCost * Math.max(inventoryLevel, 0);
double cashIncrement = (1 - overheadRate) * revenue + deposite - holdCosts - overheadCost - state.getIniCash();
double salValue = state.getPeriod() == T ? salvageValue * Math.max(inventoryLevel, 0) : 0;
cashIncrement += salValue;
double endCash = state.getIniCash() + cashIncrement;
if (endCash < 0) {
cashIncrement += penaltyCost * endCash;
}
return cashIncrement;
};
// state transition function
StateTransitionFunction<CashState, Double, Double, CashState> stateTransition = (state, action, randomDemand) -> {
double nextInventory = Math.max(0, state.getIniInventory() + action - randomDemand);
double nextCash = state.getIniCash() + immediateValue.apply(state, action, randomDemand);
nextCash = nextCash > maxCashState ? maxCashState : nextCash;
nextCash = nextCash < minCashState ? minCashState : nextCash;
nextInventory = nextInventory > maxInventoryState ? maxInventoryState : nextInventory;
nextInventory = nextInventory < minInventoryState ? minInventoryState : nextInventory;
// cash is integer or not
// the right should be a decimal
nextCash = Math.round(nextCash * 10) / 10.0;
return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
};
/**
*****************************************************************
* Solve
*/
CashRecursion recursion = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition, immediateValue, discountFactor);
int period = 1;
CashState initialState = new CashState(period, iniInventory, iniCash);
long currTime = System.currentTimeMillis();
recursion.setTreeMapCacheAction();
double finalValue = iniCash + recursion.getExpectedValue(initialState);
System.out.println("final optimal cash is " + finalValue);
System.out.println("optimal order quantity in the first priod is : " + recursion.getAction(initialState));
double time = (System.currentTimeMillis() - currTime) / 1000;
System.out.println("running time is " + time + "s");
/**
*****************************************************************
* Simulating sdp results
* parameter vales like price, variCost, holdingCost etc.
* are only for compute L(y), not very necessary
*/
int sampleNum = 10000;
// no need to add overheadCost in this class
CashSimulation simulation = new CashSimulation(distributions, sampleNum, recursion, discountFactor);
double simFinalValue = simulation.simulateSDPGivenSamplNum(initialState);
double error = 0.0001;
double confidence = 0.95;
simulation.simulateSDPwithErrorConfidence(initialState, error, confidence);
double defaultRisk = simulation.simulateDefaultProb(initialState);
System.out.println("default risk is " + defaultRisk);
/**
*****************************************************************
* Find (s, C1, C2 S) by SDP and simulate
*/
// System.out.println("");
// double[][] optTable = recursion.getOptTable();
// FindsCS findsCS = new FindsCS(iniCash, distributions, fixOrderCost, price, variCost, holdingCost, salvageValue);
// double[][] optsC12S = findsCS.getsC12S(optTable, overheadCost, criteria);
// Map<State, Double> cacheC1Values = new TreeMap<>();
// Map<State, Double> cacheC2Values = new TreeMap<>();
// double simsCSFinalValue = simulation.simulatesCS(initialState, optsC12S, cacheC1Values, cacheC2Values,
// overheadCost, maxOrderQuantity, fixOrderCost, variCost);
// double gap1 = (finalValue -simsCSFinalValue)/finalValue;
// double gap2 = (simFinalValue -simsCSFinalValue)/simFinalValue;
// System.out.printf("Optimality gap for (s, C1, C2 S) is: %.2f%% or %.2f%%\n", gap1 * 100, gap2 * 100);
//
// /*******************************************************************
// * Find (s, C1, S) by SDP and simulate
// */
// System.out.println("");
// System.out.println("************************************************");
// double[][] optsCS = findsCS.getsCS(optTable, overheadCost, criteria);
// cacheC1Values = findsCS.cacheC1Values;
// simsCSFinalValue = simulation.simulatesCS(initialState, optsCS, cacheC1Values,
// overheadCost, maxOrderQuantity, fixOrderCost, variCost);
// double gap21 = (finalValue -simsCSFinalValue)/finalValue;
// double gap22 = (simFinalValue -simsCSFinalValue)/simFinalValue;
// System.out.printf("Optimality gap for (s, C1, S) is: %.2f%% or %.2f%%\n", gap21 * 100, gap22 * 100);
// double[][] numFrequency = findsCS.getMaxSFrequency(optTable, overheadCost, criteria);
// System.out.println("most frequent S in each period");
// System.out.println(Arrays.deepToString(numFrequency));
/**
*****************************************************************
* Find (s, meanC, S) by SDP and simulate
*/
// System.out.println("");
// System.out.println("************************************************");
// optsCS = findsCS.getsCS(optTable, overheadCost, FindCCrieria.AVG);
// simsCSFinalValue = simulation.simulatesMeanCS(initialState, optsCS, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
// double gap31 = (finalValue -simsCSFinalValue)/finalValue;
// double gap32 = (simFinalValue -simsCSFinalValue)/simFinalValue;
// System.out.printf("Optimality gap for (s, meanC, S) is: %.2f%% or %.2f%%\n", gap31 * 100, gap32 * 100);
/**
*****************************************************************
* Check (s, C1, C2, S) policy,
* sometimes not always hold, because in certain period
* for some state C is 12, and 13 in other state,
* we use heuristic step by choosing maximum one
*/
// findsCS.checksCS(optsCS, optTable, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
// System.out.printf(
// "\n*******************************************************************\n");
/**
*****************************************************************
* Find (s, C, S) by MIP and simulate
*/
// System.out.println("************************************************");
// MipCashConstraint mipHeuristic = new MipCashConstraint(iniInventory, iniCash, fixOrderCost, variCost, holdingCost, price, salvageValue, distributions, overheadCost);
// double[][] sCS = mipHeuristic.findsCSPieceWise();
// Map<State, Double> cacheCValues = new TreeMap<>();
// cacheCValues = mipHeuristic.cacheC1Values;
// double simsCSMIPValue = simulation.simulatesCS(initialState, sCS, cacheCValues, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
// gap1 = (finalValue - simsCSMIPValue)/finalValue;
// gap2 = (simFinalValue - simsCSMIPValue)/simFinalValue;
// System.out.printf("Optimality gap is: %.2f%% or %.2f%%\n", gap1 * 100, gap2 * 100);
// /*******************************************************************
// * Check CK-convexity
// */
//
// // immediate value
// boolean isForDrawGy = true;
// ImmediateValueFunction<CashState, Double, Double, Double> immediateValue2 = (state, action, randomDemand) -> {
// double revenue = 0;
// double fixedCost = 0;
// double variableCost = 0;
// double inventoryLevel = 0;
// if (isForDrawGy == true && state.getPeriod() == 1) {
// revenue = price * Math.min(state.getIniInventory(), randomDemand);
// fixedCost = 0;
// variableCost = variCost * state.getIniInventory();
// inventoryLevel = state.getIniInventory() - randomDemand;
// } else {
// revenue = price * Math.min(state.getIniInventory() + action, randomDemand);
// fixedCost = action > 0 ? fixOrderCost : 0;
// variableCost = variCost * action;
// inventoryLevel = state.getIniInventory() + action - randomDemand;
// }
// double holdCosts = holdingCost * Math.max(inventoryLevel, 0);
// double cashIncrement = revenue - fixedCost - variableCost - holdCosts - overheadCost;
// double salValue = state.getPeriod() == T ? salvageValue * Math.max(inventoryLevel, 0) : 0;
// cashIncrement += salValue;
// return cashIncrement;
// };
//
// // state transition function 2
// StateTransitionFunction<CashState, Double, Double, CashState> stateTransition2 = (state, action,
// randomDemand) -> {
// double nextInventory = isForDrawGy && state.getPeriod() == 1 ? state.getIniInventory() - randomDemand
// : state.getIniInventory() + action - randomDemand;
// double nextCash = state.getIniCash() + immediateValue2.apply(state, action, randomDemand);
// if (isForDrawGy == true && state.getPeriod() == 1) // this is the only difference with transition function3
// nextCash -= fixOrderCost;
// nextCash = nextCash > maxCashState ? maxCashState : nextCash;
// nextCash = nextCash < minCashState ? minCashState : nextCash;
// nextInventory = nextInventory > maxInventoryState ? maxInventoryState : nextInventory;
// nextInventory = nextInventory < minInventoryState ? minInventoryState : nextInventory;
// return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
// };
//
//
// int minInventorys = 0;
// int maxInventorys = 50; // for drawing pictures
// int xLength = maxInventorys - minInventorys + 1;
// int index = 0;
// CashRecursion recursion2 = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition2,
// immediateValue2, discountFactor);
// double[][] yG2 = new double[xLength][2];
// index = 0;
// for (int initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
// yG2[index][0] = initialInventory;
// yG2[index][1] = -recursion2.getExpectedValue(new CashState(period, initialInventory, iniCash));
// index++;
// }
//
// int capacity = (int) Math.max(0, (iniCash - overheadCost - fixOrderCost) / variCost);
// Drawing drawing = new Drawing();
// drawing.drawSimpleG(yG2, iniCash, "K transfered in cash GB"); // GB
// System.out.println();
// System.out.println("CK convex of GB:");
// CheckKConvexity.checkCK(yG2, fixOrderCost, capacity); // check the CK convex of GB
// System.out.println();
//
}
use of milp.MipCashConstraint in project Stochastic-Inventory by RobinChen121.
the class MIPTesting method main.
public static void main(String[] args) {
String headString = "K, v, h, I0, price, salvageValue, B0, DemandPatt, Time(sec), simMIPValue";
WriteToCsv.writeToFile("./" + "testMIP_results.csv", headString);
double[][] iniMeanDemands = { { 15, 15, 15, 15, 15, 15, 15, 15 }, { 21.15, 18.9, 17.7, 16.5, 15.15, 13.95, 12.75, 11.55 }, { 6.6, 9.3, 11.1, 12.9, 16.8, 21.6, 24, 26.4 }, { 9, 13, 20, 16, 10, 16, 22, 15 }, { 22, 18, 11, 16, 22, 12, 14, 21 }, { 41.8, 6.6, 2, 21.8, 44.8, 9.6, 2.6, 17 }, { 4.08, 12.16, 37.36, 21.44, 39.12, 35.68, 19.84, 22.48 }, { 4.7, 8.1, 23.6, 39.4, 16.4, 28.7, 50.8, 39.1 }, { 4.4, 11.6, 26.4, 14.4, 14.6, 19.8, 7.4, 18.3 }, { 4.9, 18.8, 6.4, 27.9, 45.3, 22.4, 22.3, 51.7 } };
double[] K = { 10, 20 };
double[] v = { 1, 3 };
// ini cash can order 5 or 10 items
double[] B0 = { 5, 10 };
double[] p = { 4, 8 };
double[] h = { 1, 3 };
double salvageValue = 0.5;
// generally 1 for the cash constrained problem
double discountFactor = 1;
// minimum cash balance the retailer can withstand
double minCashRequired = 0;
// maximum ordering quantity when having enough cash
double maxOrderQuantity = 200;
double minInventoryState = 0;
double maxInventoryState = 500;
// can affect results, should be smaller than minus fixedOrderCost
double minCashState = -100;
double maxCashState = 2000;
double overheadCost = 0;
/**
*****************************************************************
* set demands length, for testing
*/
int newLength = 8;
double[][] meanDemands = new double[iniMeanDemands.length][newLength];
for (int i = 0; i < iniMeanDemands.length; i++) for (int j = 0; j < newLength; j++) {
meanDemands[i][j] = iniMeanDemands[i][j];
}
for (int idemand = 0; idemand < 10; idemand++) for (int iK = 0; iK < K.length; iK++) for (int iv = 0; iv < v.length; iv++) for (int ip = 0; ip < p.length; ip++) for (int ih = 0; ih < h.length; ih++) for (int iB = 0; iB < B0.length; iB++) {
double[] meanDemand = meanDemands[idemand];
double fixOrderCost = K[iK];
double variCost = v[iv];
double price = p[ip];
double iniCash = fixOrderCost + variCost * B0[iB];
double holdingCost = h[ih];
double iniInventory = 0;
// get demand possibilities for each period
int T = meanDemand.length;
Distribution[] distributions = IntStream.iterate(0, i -> i + 1).limit(T).mapToObj(// can be changed to other
i -> new PoissonDist(meanDemand[i])).toArray(PoissonDist[]::new);
// immediate value
ImmediateValueFunction<CashState, Double, Double, Double> immediateValue = (state, action, randomDemand) -> {
double revenue = price * Math.min(state.getIniInventory() + action, randomDemand);
double fixedCost = action > 0 ? fixOrderCost : 0;
double variableCost = variCost * action;
double inventoryLevel = state.getIniInventory() + action - randomDemand;
double holdCosts = holdingCost * Math.max(inventoryLevel, 0);
double cashIncrement = revenue - fixedCost - variableCost - holdCosts;
double salValue = state.getPeriod() == T ? salvageValue * Math.max(inventoryLevel, 0) : 0;
cashIncrement += salValue;
return cashIncrement;
};
// state transition function
StateTransitionFunction<CashState, Double, Double, CashState> stateTransition = (state, action, randomDemand) -> {
double nextInventory = Math.max(0, state.getIniInventory() + action - randomDemand);
double revenue = price * Math.min(state.getIniInventory() + action, randomDemand);
double fixedCost = action > 0 ? fixOrderCost : 0;
double variableCost = variCost * action;
double holdCosts = holdingCost * Math.max(nextInventory, 0);
double nextCash = state.getIniCash() + revenue - fixedCost - variableCost - holdCosts;
nextCash = nextCash > maxCashState ? maxCashState : nextCash;
nextCash = nextCash < minCashState ? minCashState : nextCash;
nextInventory = nextInventory > maxInventoryState ? maxInventoryState : nextInventory;
nextInventory = nextInventory < minInventoryState ? minInventoryState : nextInventory;
// cash is integer or not
nextCash = Math.round(nextCash * 1) / 1;
return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
};
/**
*****************************************************************
* Find (s, C, S) by MIP and simulate
*/
Map<State, Double> cacheC1Values = new TreeMap<>();
long currTime = System.currentTimeMillis();
MipCashConstraint mipHeuristic = new MipCashConstraint(iniInventory, iniCash, fixOrderCost, variCost, holdingCost, price, salvageValue, distributions, overheadCost);
int period = 1;
int sampleNum = 10000;
CashState initialState = new CashState(period, iniInventory, iniCash);
double[][] sCS = mipHeuristic.findsCS();
double time = (System.currentTimeMillis() - currTime) / 1000;
System.out.println("running time is " + time + "s");
CashSimulation simuation = new CashSimulation(distributions, sampleNum, immediateValue, stateTransition, discountFactor);
cacheC1Values = mipHeuristic.cacheC1Values;
double simsCSMIPValue = simuation.simulatesCS(initialState, sCS, cacheC1Values, minCashRequired, maxOrderQuantity, fixOrderCost, variCost);
String out = fixOrderCost + ",\t" + variCost + ",\t" + holdingCost + ",\t" + iniInventory + ",\t" + price + ",\t" + salvageValue + ",\t" + iniCash + ",\t" + (idemand + 1) + ",\t" + time + ",\t" + simsCSMIPValue;
WriteToCsv.writeToFile("./" + "testMIP_results.csv", out);
}
}
use of milp.MipCashConstraint in project Stochastic-Inventory by RobinChen121.
the class CashConstraintTest method main.
// d=[10, 10, 10, 10], coe = 10, iniCash=20, K=0; price=1.3, v=1; h = 0, salvageValue = 0.5, interestRate = 0.1
public static void main(String[] args) {
double[] meanDemand = { 20, 7, 2, 14 };
double iniInventory = 0;
double iniCash = 33;
double fixOrderCost = 24;
double variCost = 1;
double holdingCost = 0;
double price = 4;
double salvageValue = 0;
double interestRate = 0;
FindCCrieria criteria = FindCCrieria.XRELATE;
// minimum cash balance the retailer can withstand
double minCashRequired = 0;
// maximum ordering quantity when having enough cash
double maxOrderQuantity = 200;
double truncationQuantile = 0.9999;
// ordering quantity stepsize
double stepSize = 1;
double minInventoryState = 0;
double maxInventoryState = 500;
// can affect results, should be smaller than minus fixedOrderCost
double minCashState = -100;
double maxCashState = 2000;
double discountFactor = 1;
// get demand possibilities for each period
int T = meanDemand.length;
Distribution[] distributions = IntStream.iterate(0, i -> i + 1).limit(T).mapToObj(i -> new PoissonDist(meanDemand[i])).toArray(Distribution[]::new);
// double[] values1 = {6, 7};
// double[] probs1 = {0.95, 0.05};
// double[] values2 = {6, 7};
// double[] probs2 = {0.95, 0.05};
// DiscreteDistribution[] distributions = new DiscreteDistribution[T];
// for (int i = 0; i < T; i++) {
// if (i % 2 == 0)
// distributions[i] = new DiscreteDistribution(values1, probs1, values1.length);
// else
// distributions[i] = new DiscreteDistribution(values2, probs2, values2.length);
// }
double[][][] pmf = new GetPmf(distributions, truncationQuantile, stepSize).getpmf();
// feasible actions
Function<CashState, double[]> getFeasibleAction = s -> {
double maxQ = (int) Math.min(maxOrderQuantity, Math.max(0, (s.getIniCash() - minCashRequired - fixOrderCost) / variCost));
return DoubleStream.iterate(0, i -> i + stepSize).limit((int) maxQ + 1).toArray();
};
// immediate value
ImmediateValueFunction<CashState, Double, Double, Double> immediateValue = (state, action, randomDemand) -> {
double revenue = price * Math.min(state.getIniInventory() + action, randomDemand);
double fixedCost = action > 0 ? fixOrderCost : 0;
double variableCost = variCost * action;
double inventoryLevel = state.getIniInventory() + action - randomDemand;
double holdCosts = holdingCost * Math.max(inventoryLevel, 0);
double interests = interestRate * (state.getIniCash() - action * variCost);
double cashIncrement = revenue - fixedCost - variableCost - holdCosts + interests;
double salValue = state.getPeriod() == T ? salvageValue * Math.max(inventoryLevel, 0) : 0;
cashIncrement += salValue;
return cashIncrement;
};
// state transition function
StateTransitionFunction<CashState, Double, Double, CashState> stateTransition = (state, action, randomDemand) -> {
double nextInventory = Math.max(0, state.getIniInventory() + action - randomDemand);
double nextCash = state.getIniCash() + immediateValue.apply(state, action, randomDemand);
nextCash = nextCash > maxCashState ? maxCashState : nextCash;
nextCash = nextCash < minCashState ? minCashState : nextCash;
nextInventory = nextInventory > maxInventoryState ? maxInventoryState : nextInventory;
nextInventory = nextInventory < minInventoryState ? minInventoryState : nextInventory;
// cash is integer or not, inventory is integer or not
nextCash = Math.round(nextCash * 0.1) / 0.1;
nextInventory = Math.round(nextInventory * 0.1) / 0.1;
return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
};
/**
*****************************************************************
* Solve
*/
CashRecursion recursion = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition, immediateValue, discountFactor);
int period = 1;
CashState initialState = new CashState(period, iniInventory, iniCash);
long currTime = System.currentTimeMillis();
recursion.setTreeMapCacheAction();
double finalValue = iniCash + recursion.getExpectedValue(initialState);
System.out.println("final optimal cash is: " + finalValue);
System.out.println("optimal order quantity in the first priod is : " + recursion.getAction(initialState));
double time = (System.currentTimeMillis() - currTime) / 1000;
System.out.println("running time is " + time + "s");
/**
*****************************************************************
* Simulating sdp results
*/
int sampleNum = 10000;
CashSimulation simuation = new CashSimulation(distributions, sampleNum, recursion, discountFactor);
double simFinalValue = simuation.simulateSDPGivenSamplNum(initialState);
double error = 0.0001;
double confidence = 0.95;
simuation.simulateSDPwithErrorConfidence(initialState, error, confidence);
/**
*****************************************************************
* Find (s, C, S) by SDP and simulate
*/
System.out.println("");
double[][] optTable = recursion.getOptTable();
FindsCS findsCS = new FindsCS(iniCash, distributions, fixOrderCost, price, variCost, holdingCost, salvageValue);
double[][] optsCS = findsCS.getsCS(optTable, minCashRequired, criteria);
Map<State, Double> cacheC1Values = new TreeMap<>();
// Map<State, Double> cacheC2Values = new TreeMap<>();
cacheC1Values = findsCS.cacheC1Values;
// cacheC2Values = findsCS.cacheC2Values;
double simsCSFinalValue = simuation.simulatesCS(initialState, optsCS, cacheC1Values, minCashRequired, maxOrderQuantity, fixOrderCost, variCost);
double gap1 = (finalValue - simsCSFinalValue) / finalValue;
double gap2 = (simFinalValue - simsCSFinalValue) / simFinalValue;
System.out.printf("Optimality gap is: %.2f%% or %.2f%%\n", gap1 * 100, gap2 * 100);
/**
*****************************************************************
* Check (s, C, S) policy,
* sometimes not always hold, because in certain period
* for some state C is 12, and 13 in other state,
* we use heuristic step by choosing maximum one
*/
findsCS.checksCS(optsCS, optTable, minCashRequired, maxOrderQuantity, fixOrderCost, variCost);
System.out.printf("\n*******************************************************************\n");
/**
*****************************************************************
* Find (s, C, S) by MIP and simulate
*/
MipCashConstraint mipHeuristic = new MipCashConstraint(iniInventory, iniCash, fixOrderCost, variCost, holdingCost, price, salvageValue, distributions);
double[][] sCS = mipHeuristic.findsCS();
cacheC1Values = mipHeuristic.cacheC1Values;
double simsCSMIPValue = simuation.simulatesCS(initialState, sCS, cacheC1Values, minCashRequired, maxOrderQuantity, fixOrderCost, variCost);
gap1 = (finalValue - simsCSMIPValue) / finalValue;
gap2 = (simFinalValue - simsCSMIPValue) / simFinalValue;
System.out.printf("Optimality gap is: %.2f%% or %.2f%%\n", gap1 * 100, gap2 * 100);
/**
*****************************************************************
* Check K-convexity
*/
// int minInventorys = 0;
// int maxInventorys = 100;
// int xLength = maxInventorys - minInventorys + 1;
// double[][] yG = new double[xLength][2];
// int index = 0;
// for (int initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
// yG[index][0] = initialInventory;
// yG[index][1] = -recursion.getExpectedValue(new CashState(period, initialInventory, iniCash));
// index++;
// }
// int capacity = (int) Math.max(0, (iniCash - minCashRequired - fixOrderCost) / variCost);
// CheckKConvexity.checkCK(yG, fixOrderCost, capacity);
}
use of milp.MipCashConstraint in project Stochastic-Inventory by RobinChen121.
the class CashConstraintTesting method main.
// average computation time for 10 periods is 500s, 9 periods is 150s, or 305s,
// or 400s
public static void main(String[] args) {
String headString = "K, v, h, I0, price, salvageValue, B0, DemandPatt, OptValue, Time(sec), simValue, " + "totalStates, " + "simsC1C2SValue, gap1, gap2, " + "simsC1SValue, gap1, gap2, " + "simsMeanCSValue, gap1, gap2, " + "firstQ, capacity, mipValue, gap11, gap22, time2";
WriteToCsv.writeToFile("./" + "test_results.csv", headString);
double[][] iniMeanDemands = { { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }, { 21.15, 18.9, 17.7, 16.5, 15.15, 13.95, 12.75, 11.55, 10.35, 9.15 }, { 6.6, 9.3, 11.1, 12.9, 16.8, 21.6, 24, 26.4, 31.5, 33.9 }, { 12.1, 10, 7.9, 7, 7.9, 10, 12.1, 13, 12.1, 10 }, { 15.7, 10, 4.3, 2, 4.3, 10, 15.7, 18, 15.7, 10 }, { 41.8, 6.6, 2, 21.8, 44.8, 9.6, 2.6, 17, 30, 35.4 }, { 4.08, 12.16, 37.36, 21.44, 39.12, 35.68, 19.84, 22.48, 29.04, 12.4 }, { 4.7, 8.1, 23.6, 39.4, 16.4, 28.7, 50.8, 39.1, 75.4, 69.4 }, { 4.4, 11.6, 26.4, 14.4, 14.6, 19.8, 7.4, 18.3, 20.4, 11.4 }, { 4.9, 18.8, 6.4, 27.9, 45.3, 22.4, 22.3, 51.7, 29.1, 54.7 } };
double[] K = { 10, 15, 20 };
double[] v = { 1 };
// ini cash can order 4 or 6 items
double[] B0 = { 3, 5, 7 };
// margin is 4, 5, 6
double[] p = { 5, 6, 7 };
double[] h = { 0 };
double penaltyCost = 0;
double salvageValue = 0.5;
FindCCrieria criteria = FindCCrieria.XRELATE;
double truncationQuantile = 0.999;
int stepSize = 1;
// minimum cash balance the retailer can withstand
double overheadCost = 0;
// maximum ordering quantity when having enough cash
double maxOrderQuantity = 150;
double minInventoryState = 0;
double maxInventoryState = 200;
// can affect results, should be smaller than minus fixedOrderCost
double minCashState = -100;
double maxCashState = 1500;
// generally 1 for the cash constrained problem
double discountFactor = 1;
/**
*****************************************************************
* set demands length, for testing
*/
int newLength = iniMeanDemands[0].length;
double[][] meanDemands = new double[iniMeanDemands.length][newLength];
for (int i = 0; i < iniMeanDemands.length; i++) for (int j = 0; j < newLength; j++) {
meanDemands[i][j] = iniMeanDemands[i][j];
}
for (int idemand = 0; idemand < iniMeanDemands.length; idemand++) for (int iK = 0; iK < K.length; iK++) for (int iv = 0; iv < v.length; iv++) for (int ip = 0; ip < p.length; ip++) for (int ih = 0; ih < h.length; ih++) for (int iB = 0; iB < B0.length; iB++) {
double[] meanDemand = meanDemands[idemand];
double fixOrderCost = K[iK];
double variCost = v[iv];
double price = p[ip];
double iniCash = fixOrderCost + overheadCost + variCost * B0[iB];
double holdingCost = h[ih];
double iniInventory = 0;
// get demand possibilities for each period
int T = meanDemand.length;
Distribution[] distributions = IntStream.iterate(0, i -> i + 1).limit(T).mapToObj(i -> new PoissonDist(meanDemand[i])).toArray(Distribution[]::new);
double[][][] pmf = new GetPmf(distributions, truncationQuantile, stepSize).getpmf();
// feasible actions
Function<CashState, double[]> getFeasibleAction = s -> {
double maxQ = (int) Math.min(maxOrderQuantity, Math.max(0, (s.getIniCash() - overheadCost - fixOrderCost) / variCost));
return DoubleStream.iterate(0, i -> i + stepSize).limit((int) maxQ + 1).toArray();
};
// immediate value
ImmediateValueFunction<CashState, Double, Double, Double> immediateValue = (state, action, randomDemand) -> {
double revenue = price * Math.min(state.getIniInventory() + action, randomDemand);
double fixedCost = action > 0 ? fixOrderCost : 0;
double variableCost = variCost * action;
double inventoryLevel = state.getIniInventory() + action - randomDemand;
double holdCosts = holdingCost * Math.max(inventoryLevel, 0);
double cashIncrement = revenue - fixedCost - variableCost - holdCosts - overheadCost;
double salValue = state.getPeriod() == T ? salvageValue * Math.max(inventoryLevel, 0) : 0;
cashIncrement += salValue;
double endCash = state.getIniCash() + cashIncrement;
if (endCash < 0) {
cashIncrement += penaltyCost * endCash;
}
return cashIncrement;
};
// state transition function
StateTransitionFunction<CashState, Double, Double, CashState> stateTransition = (state, action, randomDemand) -> {
double nextInventory = Math.max(0, state.getIniInventory() + action - randomDemand);
double nextCash = state.getIniCash() + immediateValue.apply(state, action, randomDemand);
;
nextCash = nextCash > maxCashState ? maxCashState : nextCash;
nextCash = nextCash < minCashState ? minCashState : nextCash;
nextInventory = nextInventory > maxInventoryState ? maxInventoryState : nextInventory;
nextInventory = nextInventory < minInventoryState ? minInventoryState : nextInventory;
// cash is integer or not
nextCash = Math.round(nextCash * 1) / 1;
return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
};
/**
*****************************************************************
* Solve
*/
CashRecursion recursion = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition, immediateValue, discountFactor);
int period = 1;
CashState initialState = new CashState(period, iniInventory, iniCash);
long currTime = System.currentTimeMillis();
recursion.setTreeMapCacheAction();
double finalValue = recursion.getExpectedValue(initialState) + iniCash;
System.out.println("final optimal expected cash is: " + finalValue);
double firstQ = recursion.getAction(initialState);
System.out.println("optimal order quantity in the first priod is : " + firstQ);
double time = (System.currentTimeMillis() - currTime) / 1000.0;
System.out.println("running time is " + time + "s");
/**
*****************************************************************
* Simulating sdp results
*/
int sampleNum = 100000;
CashSimulation simuation = new CashSimulation(distributions, sampleNum, recursion, discountFactor);
double simFinalValue = simuation.simulateSDPGivenSamplNum(initialState);
/**
*****************************************************************
* Find (s, C1, C2, S) and simulate
*/
System.out.println("");
System.out.println("************************************************");
double[][] optTable = recursion.getOptTable();
FindsCS findsCS = new FindsCS(iniCash, distributions, fixOrderCost, price, variCost, holdingCost, salvageValue);
double[][] optsCS = findsCS.getsC12S(optTable, overheadCost, criteria);
Map<State, Double> cacheC1Values = new TreeMap<>();
Map<State, Double> cacheC2Values = new TreeMap<>();
cacheC1Values = findsCS.cacheC1Values;
cacheC2Values = findsCS.cacheC2Values;
double simsC1C2SFinalValue = simuation.simulatesCS(initialState, optsCS, cacheC1Values, cacheC2Values, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
double gapsC1C2S1 = (finalValue - simsC1C2SFinalValue) / finalValue;
double gapsC1C2S2 = (simFinalValue - simsC1C2SFinalValue) / simFinalValue;
System.out.printf("Optimality gap for (s, C1, C2, S) is: %.2f%% or %.2f%%\n", gapsC1C2S1 * 100, gapsC1C2S2 * 100);
/**
*****************************************************************
* Find (s, C1, S) and simulate
*/
System.out.println("");
System.out.println("************************************************");
optsCS = findsCS.getsCS(optTable, overheadCost, criteria);
cacheC1Values = findsCS.cacheC1Values;
double simsC1SFinalValue = simuation.simulatesCS(initialState, optsCS, cacheC1Values, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
double gapsC1S1 = (finalValue - simsC1SFinalValue) / finalValue;
double gapsC1S2 = (simFinalValue - simsC1SFinalValue) / simFinalValue;
System.out.printf("Optimality gap for (s, C1, S) is: %.2f%% or %.2f%%\n", gapsC1S1 * 100, gapsC1S2 * 100);
double[][] numFrequency = findsCS.getMaxSFrequency(optTable, overheadCost, criteria);
// System.out.println("most frequent S in each period");
// System.out.println(Arrays.deepToString(numFrequency));
/**
*****************************************************************
* Find (s, meanC, S) by SDP and simulate
*/
System.out.println("");
System.out.println("************************************************");
optsCS = findsCS.getsCS(optTable, overheadCost, FindCCrieria.AVG);
double simsMeanCSFinalValue = simuation.simulatesMeanCS(initialState, optsCS, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
double gapsMeanCS1 = (finalValue - simsMeanCSFinalValue) / finalValue;
double gapsMeanCS2 = (simFinalValue - simsMeanCSFinalValue) / simFinalValue;
System.out.printf("Optimality gap for (s, meanC, S) is: %.2f%% or %.2f%%\n", gapsMeanCS1 * 100, gapsMeanCS2 * 100);
// /*******************************************************************
// * Check (s, C, S) policy, sometimes not always hold
// */
// int nonOptCount = findsCS.checksCS(optsCS, optTable, overheadCost, maxOrderQuantity,
// fixOrderCost, variCost);
/**
*****************************************************************
* Find (s, C, S) by MIP and simulate
*/
double simsCSMIPValue = 0;
double gap11 = 0;
double gap22 = 0;
double time2 = 0;
currTime = System.currentTimeMillis();
MipCashConstraint mipHeuristic = new MipCashConstraint(iniInventory, iniCash, fixOrderCost, variCost, holdingCost, price, salvageValue, distributions, overheadCost);
double[][] sCS = mipHeuristic.findsCSPieceWise();
time2 = (System.currentTimeMillis() - currTime) / 1000.0;
System.out.println("running time is " + time2 + "s");
cacheC1Values = mipHeuristic.cacheC1Values;
simsCSMIPValue = simuation.simulatesCS(initialState, sCS, cacheC1Values, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
gap11 = (finalValue - simsCSMIPValue) / finalValue;
gap22 = (simFinalValue - simsCSMIPValue) / simFinalValue;
System.out.printf("Optimality gap by Mip is: %.2f%% or %.2f%%\n", gap11 * 100, gap22 * 100);
System.out.printf("\n*******************************************************************\n");
//
String convexity = "";
// double[][] yG = new double[xLength][2];
// index = 0;
// for (int initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
// yG[index][0] = initialInventory;
// yG[index][1] = -recursion2
// .getExpectedValue(new CashState(period, initialInventory, iniCash));
// index++;
// }
// convexity = CheckKConvexity.checkCK(yG3, fixOrderCost, capacity);
// System.out.printf(
// "\n*******************************************************************\n");
long totalStates = optTable.length;
String out = fixOrderCost + ",\t" + variCost + ",\t" + holdingCost + ",\t" + iniInventory + ",\t" + price + ",\t" + salvageValue + ",\t" + iniCash + ",\t" + (idemand + 1) + ",\t" + finalValue + ",\t" + time + ",\t" + simFinalValue + ",\t" + totalStates + ",\t" + simsC1C2SFinalValue + ",\t" + gapsC1C2S1 + ",\t" + gapsC1C2S2 + ",\t" + simsC1SFinalValue + ",\t" + gapsC1S1 + ",\t" + gapsC1S2 + ",\t" + simsMeanCSFinalValue + ",\t" + gapsMeanCS1 + ",\t" + gapsMeanCS2 + ",\t" + firstQ + ",\t" + B0[iB] + ",\t" + simsCSMIPValue + ",\t" + gap11 + ",\t" + gap22 + ",\t" + time2;
WriteToCsv.writeToFile("./" + "test_results.csv", out);
}
}
Aggregations