use of sdp.cash.CashState in project Stochastic-Inventory by RobinChen121.
the class CheckFG method main.
public static void main(String[] args) {
double[] meanDemand = { 8, 8, 8 };
double iniCash = 13;
double iniInventory = 0;
double fixOrderCost = 10;
double variCost = 1;
double price = 8;
double salvageValue = 0.5;
double holdingCost = 0;
// minimum cash balance the retailer can withstand
double overheadCost = 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 = -100;
double maxCashState = 2000;
double discountFactor = 1;
boolean isForDrawGy = true;
// 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 = 0;
double fixedCost = 0;
double variableCost = 0;
double inventoryLevel = 0;
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;
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 = 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;
// nextCash = Math.round(nextCash * 100) / 100.00;
return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
};
/**
*****************************************************************
* Solve F(x, R)
*/
int minInventorys = 0;
// for drawing pictures
int maxInventorys = 100;
int minCash = 0;
int maxCash = (int) fixOrderCost + 80;
int RLength = maxCash - minCash + 1;
int xLength = maxInventorys - minInventorys + 1;
int period = 1;
int index = 0;
int rowIndex = 0;
int columnIndex = 0;
long currTime = System.currentTimeMillis();
CashRecursion recursion = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition, immediateValue, discountFactor);
double[][] yG = new double[xLength * RLength][3];
double[][] resultTableF = new double[RLength][xLength];
double[][] resultTableQ = new double[RLength][xLength];
for (double initialCash = minCash; initialCash <= maxCash; initialCash++) {
columnIndex = 0;
for (double initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
// initialInventory
yG[index][0] = initialCash;
yG[index][1] = initialInventory;
// iniCash
yG[index][2] = recursion.getExpectedValue(new CashState(period, initialInventory, initialCash));
resultTableF[rowIndex][columnIndex] = yG[index][2];
resultTableQ[rowIndex][columnIndex] = recursion.getAction(new CashState(period, initialInventory, initialCash));
index++;
columnIndex++;
}
rowIndex++;
}
// immediate value for GB and GA
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;
// variCost * state.getIniInventory(); // be careful
variableCost = 0;
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 for GA
StateTransitionFunction<CashState, Double, Double, CashState> stateTransition3 = (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);
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);
};
CashRecursion recursion3 = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition3, immediateValue2, discountFactor);
double[][] yG3 = new double[xLength * RLength][3];
index = 0;
double[][] resultTableGA = new double[xLength][RLength];
rowIndex = 0;
for (double initialInventory = minInventoryState; initialInventory <= maxInventorys; initialInventory++) {
columnIndex = 0;
for (double initialCash = minCash; initialCash <= maxCash; initialCash++) {
// initialInventory
yG3[index][0] = initialInventory;
// initialCash
yG3[index][1] = initialCash;
yG3[index][2] = recursion3.getExpectedValue(new CashState(period, initialInventory, initialCash)) - variCost * initialInventory;
// careful, minus cy
resultTableGA[rowIndex][columnIndex] = yG3[index][2];
index++;
columnIndex++;
}
rowIndex++;
}
double[][] resultH = recursion3.getH(resultTableGA, minCash, fixOrderCost, variCost);
System.out.println("Single-crossing property: " + recursion3.checkSingleCrossing(resultH));
WriteToCsv wr = new WriteToCsv();
wr.writeArrayCSVLabel(resultTableQ, minCash, minInventorys, "Q.csv");
wr.writeArrayCSVLabel(resultTableF, minCash, minInventorys, "F.csv");
wr.writeArrayCSVLabel(resultTableGA, minCash, minInventorys, "G.csv");
wr.writeArrayCSVLabel(resultH, minCash, minInventorys, "H.csv");
// wr.writeArrayCSV(recursion3.getH3Column(resultTableGA, minCash, fixOrderCost, variCost), "G3column.csv");
double time = (System.currentTimeMillis() - currTime) / 1000;
System.out.println("running time is " + time + "s");
}
use of sdp.cash.CashState in project Stochastic-Inventory by RobinChen121.
the class SingleCrossTesting method main.
public static void main(String[] args) {
String headString = "K, v, h, price, salvageValue, DemandPatt, Single-crossing";
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 };
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 salvageValue = 0;
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;
boolean isForDrawGy = true;
/**
*****************************************************************
* set demands length, for testing
*/
int TLength = 2;
double[][] meanDemands = new double[iniMeanDemands.length][TLength];
for (int i = 0; i < iniMeanDemands.length; i++) for (int j = 0; j < TLength; j++) {
meanDemands[i][j] = iniMeanDemands[i][j];
}
for (int idemand = 0; idemand < meanDemands.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++) {
double[] meanDemand = meanDemands[idemand];
double fixOrderCost = K[iK];
double variCost = v[iv];
double price = p[ip];
double holdingCost = h[ih];
int minInventorys = 0;
// for drawing pictures
int maxInventorys = 30;
int minCash = 0;
int maxCash = (int) fixOrderCost + 30;
int RLength = maxCash - minCash + 1;
int xLength = maxInventorys - minInventorys + 1;
int period = 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[][][] 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 = 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;
// variCost * state.getIniInventory(); // be careful
variableCost = 0;
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
StateTransitionFunction<CashState, Double, Double, CashState> stateTransition = (state, action, randomDemand) -> {
double nextInventory = isForDrawGy && state.getPeriod() == 1 ? state.getIniInventory() - randomDemand : 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;
return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
};
long currTime = System.currentTimeMillis();
CashRecursion recursion = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition, immediateValue, discountFactor);
double[][] yG = new double[xLength * RLength][3];
int index = 0;
double[][] resultTableG = new double[RLength][xLength];
int rowIndex = 0;
int columnIndex = 0;
for (double initialCash = minCash; initialCash <= maxCash; initialCash++) {
columnIndex = 0;
for (double initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
// initialInventory
yG[index][0] = initialCash;
// initialInventory
yG[index][1] = initialInventory;
yG[index][2] = recursion.getExpectedValue(new CashState(period, initialInventory, initialCash)) - variCost * initialInventory;
// careful, minus cy
resultTableG[rowIndex][columnIndex] = yG[index][2];
index++;
columnIndex++;
}
rowIndex++;
}
double[][] resultH = recursion.getH(resultTableG, minCash, fixOrderCost, variCost);
boolean singleCrossing = recursion.checkSingleCrossing(resultH);
System.out.println("Single-crossing property: " + singleCrossing);
double time = (System.currentTimeMillis() - currTime) / 1000.0;
System.out.println("running time is " + time + "s");
String out = fixOrderCost + ",\t" + variCost + ",\t" + holdingCost + ",\t" + price + ",\t" + salvageValue + ",\t" + (idemand + 1) + ",\t" + singleCrossing;
WriteToCsv.writeToFile("./" + "test_results.csv", out);
}
}
use of sdp.cash.CashState in project Stochastic-Inventory by RobinChen121.
the class cashSurvival method main.
/**
* @param args
* @date: Nov 21, 2020, 6:01:10 PM
*/
public static void main(String[] args) {
double[] meanDemand = { 5, 5, 5, 5 };
// 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 = 15;
double fixOrderCost = 0;
double variCost = 1;
double[] price = { 3, 3, 3, 3 };
double depositeRate = 0;
double salvageValue = 0.5;
double holdingCost = 0;
FindCCrieria criteria = FindCCrieria.XRELATE;
// costs like wages or rents which is required to pay in each period
double overheadCost = 10;
// 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;
// can also be overdraft rate; 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[][][] pmf = new GetPmf(distributions, truncationQuantile, stepSize).getpmf();
// feasible actions
// in fact, no cash constraint in this paper
Function<CashState, double[]> getFeasibleAction = s -> {
return DoubleStream.iterate(0, i -> i + stepSize).limit((int) maxOrderQuantity + 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) {
// can change to overdraft interest
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 * 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.getSurvProb(initialState);
System.out.println("survival probability for this initial state 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");
double[][] optTable = recursion.getOptTable();
System.out.println();
/**
*****************************************************************
* Simulate the result
*/
// immediate value
ImmediateValueFunction<CashState, Double, Double, Double> immediateValue2 = (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;
return cashIncrement;
};
int sampleNum = 100000;
// no need to add overheadCost in this class
CashSimulation simulation = new CashSimulation(distributions, sampleNum, recursion, discountFactor);
double[] result = simulation.simulateSDPGivenSamplNum(initialState, immediateValue2);
DecimalFormat df2 = new DecimalFormat("###, ###");
System.out.println("\nfinal simulated survival probability in " + df2.format(sampleNum) + " samples is: " + result[0]);
System.out.println("\nfinal simulated lost sale rate " + " is: " + result[1]);
}
use of sdp.cash.CashState 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 sdp.cash.CashState in project Stochastic-Inventory by RobinChen121.
the class CashConstraintDraw method main.
public static void main(String[] args) {
double[] meanDemand = { 7, 2, 6 };
// double[] meanDemand = {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
double iniCash = 13;
double iniInventory = 0;
double fixOrderCost = 20;
double variCost = 1;
double price = 5;
double salvageValue = 0;
double holdingCost = 0;
FindCCrieria criteria = FindCCrieria.XRELATE;
// minimum cash balance the retailer can withstand
double overheadCost = 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 = -100;
double maxCashState = 2000;
double discountFactor = 1;
boolean isForDrawGy = true;
// 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 distributions
i -> new PoissonDist(meanDemand[i])).toArray(PoissonDist[]::new);
// double[] values = {6, 7};
// double[] probs = {0.95, 0.05};
// Distribution[] distributions = IntStream.iterate(0, i -> i + 1).limit(T)
// .mapToObj(i -> new DiscreteDistribution(values, probs, values.length)) // can be changed to other distributions
// .toArray(DiscreteDistribution[]::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 = 0;
double fixedCost = 0;
double variableCost = 0;
double inventoryLevel = 0;
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;
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 = 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;
// nextCash = Math.round(nextCash * 100) / 100.00;
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 finalCash = iniCash + recursion.getExpectedValue(initialState);
System.out.println("final optimal cash is: " + finalCash);
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) and simulate
*/
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 simsCSFinalValue = simuation.simulatesCS(initialState, optsCS, cacheC1Values, cacheC2Values, overheadCost, maxOrderQuantity, fixOrderCost, variCost);
double gap1 = (finalCash - simsCSFinalValue) / finalCash;
double gap2 = (simFinalValue - simsCSFinalValue) / simFinalValue;
System.out.printf("Optimality gap is: %.2f%% or %.2f%%\n", gap1 * 100, gap2 * 100);
/**
*****************************************************************
* Drawing x Q
*/
int minInventorys = 0;
// for drawing pictures
int maxInventorys = 30;
int minCash = (int) fixOrderCost;
int maxCash = (int) (fixOrderCost + 50);
int RLength = maxCash - minCash + 1;
int xLength = maxInventorys - minInventorys + 1;
Drawing drawing = new Drawing();
double initialInventory = 0;
// double[][] xQ = new double[xLength][2];
// int index = 0;
// for (initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
// //for (double initialCash = minCash; initialCash <= maxCash; initialCash++) {
// period = 1;
// xQ[index][0] = initialInventory;
// recursion.getExpectedValue(new CashState(period, initialInventory, iniCash));
// xQ[index][1] = recursion.getAction(new CashState(period, initialInventory, iniCash));
// index++;
// }
// drawing.drawXQ(xQ);
/**
*****************************************************************
* Drawing y G since comupteIfAbsent, we need initializing a new class to draw
* Gy; if not, java would not compute sdp again, we must redefine
* stateTransition function and immediate Function;
*/
// immediate value for GB
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, for GB
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)
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);
};
CashRecursion recursion2 = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition2, immediateValue2, discountFactor);
double[][] yG2 = new double[xLength * RLength][3];
int index = 0;
double[][] resultTableGB = new double[RLength][xLength];
int rowIndex = 0;
int columnIndex = 0;
for (double initialCash = minCash; initialCash <= maxCash; initialCash++) {
columnIndex = 0;
for (initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
// initialInventory
yG2[index][0] = initialCash;
yG2[index][1] = initialInventory;
// iniCash
yG2[index][2] = recursion2.getExpectedValue(new CashState(period, initialInventory, initialCash));
resultTableGB[rowIndex][columnIndex] = yG2[index][2];
index++;
columnIndex++;
}
rowIndex++;
}
WriteToCsv wr = new WriteToCsv();
wr.writeArrayCSV(resultTableGB, "GB.csv");
// CheckKConvexity.check(yG2, fixOrderCost);
// drawing.drawSimpleG(yG2, iniCash, "K transfered in cash GB"); // GB
/**
*****************************************************************
* Drawing another G() that has no fixed ordering cost transition in the
* first period, GA
* the difference lies in state transition function
*/
// state transition function 3
StateTransitionFunction<CashState, Double, Double, CashState> stateTransition3 = (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);
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);
};
CashRecursion recursion3 = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction, stateTransition3, immediateValue2, discountFactor);
double[][] yG3 = new double[xLength * RLength][3];
index = 0;
double[][] resultTableGA = new double[RLength][xLength];
rowIndex = 0;
// for (int initialInventory = minInventorys; initialInventory <= maxInventorys; initialInventory++) {
for (double initialCash = minCash; initialCash <= maxCash; initialCash++) {
columnIndex = 0;
for (initialInventory = minInventoryState; initialInventory <= maxInventorys; initialInventory++) {
// initialInventory
yG3[index][0] = initialCash;
// initialInventory
yG3[index][1] = initialInventory;
// iniCash
yG3[index][2] = recursion3.getExpectedValue(new CashState(period, initialInventory, initialCash));
resultTableGA[rowIndex][columnIndex] = yG3[index][2];
index++;
columnIndex++;
}
rowIndex++;
}
double[][] resultMinusGBA = recursion.getMinusGAGB(resultTableGA, resultTableGB, minCash, fixOrderCost, variCost);
wr.writeArrayCSV(resultTableGA, "GA.csv");
wr.writeArrayCSV(resultMinusGBA, "minusGBA.csv");
// drawing.drawSimpleG(yG3, iniCash, "K not transfered in cash GA");
// drawing.drawTwoGR(yG3, yG2, initialInventory); //drawing.drawTwoG(yG3, yG2, iniCash);
// double[] interPoint = drawing.intersectionPoint(yG3, yG2, iniCash);
// String fileName= "interSectionPoints.xls";
// wr.writeToExcelAppend(interPoint, fileName);
}
Aggregations