use of milp.LostSaleChance in project Stochastic-Inventory by RobinChen121.
the class CashSimulation method simulateSAA.
/**
* simulate SAA for joint chance problem.
* @param iniState
* @param iniQ
* @param serviceRate
* @param sampleNums
* @param prices
* @param variCostUnits
* @param overheadCosts
* @param salvageValueUnit
* @param holdCostUnit
* @param scenarios
* @param sampleNum
* @return the final value with lost sale rate
*/
public double[] simulateSAA(CashState iniState, double iniQ, double serviceRate, int[] sampleNums, double[] prices, double[] variCostUnits, double[] overheadCosts, double salvageValueUnit, double holdCostUnit, double[][] scenarios, int sampleNum) {
Sampling.resetStartStream();
Sampling sampling = new Sampling();
double[][] samples = sampling.generateLHSamples(distributions, sampleNum);
double[] simuValues = new double[samples.length];
int T = samples[0].length;
int lostSaleCount = 0;
for (int i = 0; i < samples.length; i++) {
CashState state = iniState;
boolean countBeforeBankrupt = false;
boolean countLostBefore = false;
double thisValue = 0;
double optQ = 0;
double thisServiceRate = 1;
for (int t = 0; t < T; t++) {
if (t == 0) {
optQ = iniQ;
thisServiceRate = serviceRate;
}
// integer samples to test sdp
double randomDemand = Math.round(samples[i][t]);
thisValue = state.iniCash + immediateValue.apply(state, optQ, randomDemand);
if (state.getIniInventory() + optQ < randomDemand - 0.1 && countLostBefore == false) {
lostSaleCount++;
countLostBefore = true;
}
if (thisValue < -0.1 && countBeforeBankrupt == false) {
simuValues[i] = 1;
countBeforeBankrupt = true;
}
if (t < T - 1) {
// very important
double nextServiceRate = countLostBefore == true ? 0 : thisServiceRate / distributions[t].cdf(optQ + state.getIniInventory());
state = stateTransition.apply(state, optQ, randomDemand);
double iniCash = state.iniCash;
double iniI = state.getIniInventory();
double[] nextPrices = gettTArray(prices, t + 1);
int[] nextSampleNums = gettTArray(sampleNums, t + 1);
double[] nextVariCostUnits = gettTArray(variCostUnits, t + 1);
Distribution[] nexDistributions = gettTArray(distributions, t + 1);
double[] nextOverheadCosts = gettTArray(overheadCosts, t + 1);
double[][] nextScenarios = gettTArray(scenarios, t + 1);
LostSaleChance model = new LostSaleChance(nexDistributions, nextSampleNums, iniCash, iniI, nextPrices, nextVariCostUnits, salvageValueUnit, holdCostUnit, nextOverheadCosts, nextServiceRate, nextScenarios);
double[] result = model.solveMaxSurvival();
optQ = result[0];
thisServiceRate = nextServiceRate;
}
}
}
double simFinalValue = 1 - Arrays.stream(simuValues).sum() / (double) samples.length;
double lostSaleRate = (double) lostSaleCount / (double) sampleNum;
int n = samples.length;
double sigma = Math.sqrt(simFinalValue * (1 - simFinalValue) / n);
double lowCI = simFinalValue - 1.96 * sigma;
double upCI = simFinalValue + 1.96 * sigma;
double error = 1.96 * sigma;
System.out.printf("the confidence interval for simulated SAA is [%.4f, %.4f], with error is %.4f. \n", lowCI, upCI, error);
double[] result = { simFinalValue, lostSaleRate };
return result;
}
use of milp.LostSaleChance in project Stochastic-Inventory by RobinChen121.
the class ChanceCash method main.
public static void main(String[] args) {
double iniCash = 150;
double iniI = 0;
double trunQuantile = 0.999;
// the higher value results in slower running speed. maximum negative possibility rate is 1 - serviceRate.
double serviceRate = 0.6;
// sample number in each period, the number of samples in the first period can have big influence
int[] sampleNums = { 5, 5, 5, 5 };
double[] meanDemand = { 10, 5, 10, 5 };
int T = sampleNums.length;
int[] sampleNumsRolling = { 5, 5, 5, 5 };
// rolling horizon length
int rollingLength = 2;
double meanDemandSum = Arrays.stream(meanDemand).sum();
double rollingDemandSum = Arrays.stream(meanDemand).limit(rollingLength).sum();
double portion = rollingDemandSum / meanDemandSum;
double rollingServiceRate = Math.pow(serviceRate, portion);
// simulating sample number in testing SAA and extended SAA
int sampleNum = 100;
double holdCostUnit = 0;
double salvageValueUnit = 5;
double[] prices = new double[T];
double[] variCostUnits = new double[T];
double[] overheadCosts = new double[T];
double[] mus = new double[T];
double sigmasCoe = 0.25;
Arrays.fill(prices, 22);
Arrays.fill(variCostUnits, 10);
// overhead costs
Arrays.fill(overheadCosts, 100);
// Arrays.fill(mus, 3.6);
// Arrays.fill(sigmas, 0.6);
// maximum ordering quantity when having enough cash
double maxOrderQuantity = 300;
Distribution[] distributions = IntStream.iterate(0, i -> i + 1).limit(T).mapToObj(i -> new PoissonDist(meanDemand[i])).toArray(// Poisson demand
Distribution[]::new);
// .mapToObj(i -> new LognormalDist(mus[i], sigmas[i])).toArray(Distribution[]::new);
/**
* solve the problem by SAA
*/
// generate scenarios, samples in each period form a scenario tree
Sampling sampling = new Sampling();
double[][] scenarios = sampling.generateLHSamples(distributions, sampleNums);
int sampleNumTotal = IntStream.of(sampleNums).reduce(1, (a, b) -> a * b);
int sampleNumTotalSimulate = IntStream.of(sampleNumsRolling).limit(rollingLength).reduce(1, (a, b) -> a * b);
int negativeScenarioNumRequire = (int) (sampleNumTotal * (1 - serviceRate));
LostSaleChance model = new LostSaleChance(distributions, sampleNums, iniCash, iniI, prices, variCostUnits, salvageValueUnit, holdCostUnit, overheadCosts, serviceRate, scenarios);
long currTime = System.currentTimeMillis();
double[] result;
double time1;
double positiveScenario;
double survivalProb;
double lostRate;
NumberFormat nf = NumberFormat.getPercentInstance();
nf.setMinimumFractionDigits(5);
DecimalFormat df = new DecimalFormat("###, ###");
result = model.solveMaxSurvival();
time1 = (System.currentTimeMillis() - currTime) / 1000.00;
currTime = System.currentTimeMillis();
System.out.println("**********************************************");
System.out.println("result of SAA-scenario tree before sorting scenarios: ");
System.out.println("running time is " + time1 + "s");
System.out.printf("first stage decison Q is: %.2f\n", result[0]);
positiveScenario = result[1];
System.out.printf("Objective value is: %.0f in %d scenarios\n", result[1], sampleNumTotal);
survivalProb = 100 * result[1] / sampleNumTotal;
System.out.printf("Survival probability is: %.5f%%\n", survivalProb);
System.out.println("lost sale scenario number in the solution is : " + result[2]);
System.out.println("maximum lost sale scenario number allowed is: " + negativeScenarioNumRequire);
lostRate = result[2] / (double) sampleNumTotal;
System.out.println("lost sale rate of SAA is: " + nf.format(lostRate));
System.out.println("lost sale max required rate is: " + nf.format(1 - serviceRate));
System.out.println();
/**
* Simulate the restult of SAA
*/
int stepSize = 1;
double fixOrderCost = 0;
double depositeRate = 0;
double minInventoryState = 0;
double maxInventoryState = 500;
// can affect results, should be smaller than minus fixedOrderCost
double minCashState = -1000;
double maxCashState = 2000;
double discountFactor = 1;
double[][][] pmf = new GetPmf(distributions, trunQuantile, stepSize).getpmf();
// immediate value
ImmediateValueFunction<CashState, Double, Double, Double> immediateValue = (state, action, randomDemand) -> {
int t = state.getPeriod() - 1;
double revenue = prices[t] * Math.min(state.getIniInventory() + action, randomDemand);
double fixedCost = action > 0 ? fixOrderCost : 0;
double variableCost = variCostUnits[t] * action;
double deposite = (state.getIniCash() - fixedCost - variableCost) * (1 + depositeRate);
double inventoryLevel = state.getIniInventory() + action - randomDemand;
double holdCosts = holdCostUnit * Math.max(inventoryLevel, 0);
double cashIncrement = revenue + deposite - holdCosts - overheadCosts[t] - state.getIniCash();
double salValue = state.getPeriod() == T ? salvageValueUnit * 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
// the right should be a decimal
nextCash = Math.round(nextCash * 1) / 1;
return new CashState(state.getPeriod() + 1, nextInventory, nextCash);
};
int period = 1;
CashState initialState = new CashState(period, iniI, iniCash);
double[] result1;
// no need to add overheadCost in this class
CashSimulation simulation1 = new CashSimulation(distributions, sampleNum, immediateValue, stateTransition);
double error;
double thisServiceRate;
result1 = simulation1.simulateSAA(initialState, result[0], serviceRate, sampleNums, prices, variCostUnits, overheadCosts, salvageValueUnit, holdCostUnit, scenarios, sampleNum);
System.out.println("final simulated survival probability of SAA in " + df.format(sampleNum) + " samples is: " + nf.format(result1[0]));
error = 1.96 * Math.sqrt(result1[1] * (1 - result1[1]) / sampleNum);
thisServiceRate = 1 - result1[1];
System.out.println("final simulated service sale rate of SAA " + " is: " + nf.format(thisServiceRate) + " with error " + nf.format(error));
/**
* solve the problem by extended formulation of SAA,
* sort scenarios in the whole planning horizon
*/
currTime = System.currentTimeMillis();
// same result with soveSort or solveSort2, but less computational time
result = model.solveSortWhole();
// former name is solveSortFurther()
time1 = (System.currentTimeMillis() - currTime) / 1000.00;
currTime = System.currentTimeMillis();
System.out.println("**********************************************");
System.out.println("after sorting scenarios in the whole planning horizon, result of SAA-scenario tree: ");
System.out.println("running time is " + time1 + "s");
System.out.printf("first stage decison Q is: %.2f\n", result[0]);
positiveScenario = result[1];
System.out.printf("Objective value is: %.0f in %d scenarios\n", positiveScenario, sampleNumTotal);
survivalProb = 100 * result[1] / sampleNumTotal;
System.out.printf("Survival probability is: %.5f%%\n", survivalProb);
System.out.println("lost sale scenario number in the solution is : " + result[2]);
System.out.println("maximum lost sale scenario number allowed is: " + negativeScenarioNumRequire);
lostRate = result[2] / (double) sampleNumTotal;
System.out.println("lost sale rate of SAA is: " + nf.format(lostRate));
System.out.println("lost sale max required rate is: " + nf.format(1 - serviceRate));
System.out.println();
/**
* Simulate the result of extended SAA
*/
result1 = simulation1.simulateExtendSAAWhole(initialState, result[0], serviceRate, sampleNums, prices, variCostUnits, overheadCosts, salvageValueUnit, holdCostUnit, scenarios, sampleNum);
System.out.println("final simulated survival probability of extended SAA(sort whole planning horizon) in " + df.format(sampleNum) + " samples is: " + nf.format(result1[0]));
error = 1.96 * Math.sqrt(result1[1] * (1 - result1[1]) / sampleNum);
thisServiceRate = 1 - result1[1];
System.out.println("final simulated service rate of extended SAA(sort whole planning horizon) " + " is: " + nf.format(thisServiceRate) + " with error " + nf.format(error));
/**
* solve the problem by extended formulation of SAA,
* sort scenarios in each period.
*/
// currTime = System.currentTimeMillis();
// result = model.solveSortEach(); // same result with soveSort or solveSort2, but less computational time
// // former name is solveSortFurther()
//
// time1 = (System.currentTimeMillis() - currTime) / 1000.00;
// currTime = System.currentTimeMillis();
// System.out.println("**********************************************");
// System.out.println("after sorting scenarios in each period, the result of SAA-scenario tree: ");
// System.out.println("running time is " + time1 + "s");
// System.out.printf("first stage decison Q is: %.2f\n", result[0]);
// positiveScenario = result[1];
// System.out.printf("Objective value is: %.0f in %d scenarios\n", positiveScenario, sampleNumTotal);
// survivalProb = 100 * result[1] / sampleNumTotal;
// System.out.printf("Survival probability is: %.5f%%\n", survivalProb);
// System.out.println("lost sale scenario number in the solution is : " + result[2]);
// System.out.println("maximum lost sale scenario number allowed is: " + negativeScenarioNumRequire);
// lostRate = result[2] / (double) sampleNumTotal;
// System.out.println("lost sale rate of SAA is: " + nf.format(lostRate));
// System.out.println("lost sale max required rate is: " + nf.format(1 - serviceRate));
// System.out.println();
//
// /**
// * Simulate the result of extended SAA sorting each period
// */
// result1 = simulation1.simulateExtendSAAEach(initialState, result[0], serviceRate, sampleNums, prices, variCostUnits, overheadCosts, salvageValueUnit, holdCostUnit, scenarios, sampleNum);
// System.out.println("final simulated survival probability of extended SAA sorting each period in " + df.format(sampleNum) + " samples is: " + nf.format(result1[0]));
// System.out.println("final simulated lost sale rate of extended SAA sorting each period " + " is: " + nf.format(result1[1]));
/**
* solve the problem by SDP when there is no joint chance constraint
*/
// feasible actions
Function<CashState, double[]> getFeasibleAction1 = s -> {
int t = s.getPeriod() - 1;
double thisPeriodServRate = (1 - serviceRate) / T;
// double minQ = Math.ceil(distributions[t].inverseF(1 - thisPeriodServRate)); // minimum ordering quantity in each period
double minQ = 0;
return DoubleStream.iterate(minQ, i -> i + stepSize).limit((int) maxOrderQuantity + 1).toArray();
};
/**
*****************************************************************
* Solve
*/
CashRecursion recursion = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction1, stateTransition, immediateValue, discountFactor);
currTime = System.currentTimeMillis();
recursion.setTreeMapCacheAction();
double finalValue = recursion.getSurvProb(initialState);
System.out.println("**********************************************");
System.out.println("result of SDP with no service rate constraint is: ");
System.out.println("survival probability for this initial state is: " + nf.format(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
*/
sampleNum = 10000;
// no need to add overheadCost in this class
CashSimulation simulation = new CashSimulation(distributions, sampleNum, recursion, discountFactor);
double[] result2 = simulation.simulateSDPGivenSamplNum(initialState, immediateValue);
System.out.println("final simulated survival probability in " + df.format(sampleNum) + " samples is: " + nf.format(result2[0]));
System.out.println("final simulated lost sale rate " + " is: " + nf.format(result2[1]));
/**
*****************************************************************
* solve the problem by SDP when there is individual chance constraint approximation
*/
// feasible actions 2
// in fact, no cash constraint in this paper
Function<CashState, double[]> getFeasibleAction2 = s -> {
int t = s.getPeriod() - 1;
double thisPeriodServRate = (1 - serviceRate) / T;
// minimum ordering quantity in each period
double minQ = Math.ceil(distributions[t].inverseF(1 - thisPeriodServRate));
return DoubleStream.iterate(minQ, i -> i + stepSize).limit((int) maxOrderQuantity + 1).toArray();
};
/**
*****************************************************************
* Solve
*/
recursion = new CashRecursion(OptDirection.MAX, pmf, getFeasibleAction2, stateTransition, immediateValue, discountFactor);
period = 1;
initialState = new CashState(period, iniI, iniCash);
currTime = System.currentTimeMillis();
recursion.setTreeMapCacheAction();
finalValue = recursion.getSurvProb(initialState);
System.out.println("**********************************************");
System.out.println("result of SDP with service rate constraint is: ");
finalValue = finalValue * 100;
System.out.printf("survival probability for this initial state is: %.2f%%\n", finalValue);
System.out.println("optimal order quantity in the first priod is : " + recursion.getAction(initialState));
time = (System.currentTimeMillis() - currTime) / 1000;
System.out.println("running time is " + time + "s");
/**
*****************************************************************
* Simulating sdp results
*/
sampleNum = 10000;
// no need to add overheadCost in this class
simulation = new CashSimulation(distributions, sampleNum, recursion, discountFactor);
result2 = simulation.simulateSDPGivenSamplNum(initialState, immediateValue);
System.out.println("final simulated survival probability in " + df.format(sampleNum) + " samples is: " + nf.format(result2[0]));
System.out.println("final simulated lost sale rate " + " is: " + nf.format(result2[1]));
/**
* solve the problem by rolling horizon of further SAA
*/
// number of scenarios for rolling SAA
sampleNum = 100;
currTime = System.currentTimeMillis();
System.out.println("**********************************************");
result1 = simulation1.rollingHoirzonFurtherExtendSAA(rollingLength, initialState, rollingServiceRate, sampleNumsRolling, prices, variCostUnits, overheadCosts, salvageValueUnit, holdCostUnit, scenarios, sampleNum);
time1 = (System.currentTimeMillis() - currTime) / 1000.00;
System.out.println("after rolling horizon for length " + rollingLength + ", result of SAA-scenario tree: ");
System.out.println("running time is " + time1 + "s");
System.out.println("final simulated survival probability of rolling further SAA in " + df.format(sampleNum) + " samples is: " + nf.format(result1[0]));
System.out.println("final simulated lost sale rate of rolling further SAA " + " is: " + nf.format(result1[1]));
}
use of milp.LostSaleChance in project Stochastic-Inventory by RobinChen121.
the class CashSimulation method simulateExtendSAAWhole.
/**
* simulate the extended SAA sorting the whole planning horizon.
* @param iniState
* @param iniQ
* @param serviceRate
* @param sampleNums
* @param prices
* @param variCostUnits
* @param overheadCosts
* @param salvageValueUnit
* @param holdCostUnit
* @param scenarios
* @param sampleNum
* @return the final value with lost sale rate.
*/
public double[] simulateExtendSAAWhole(CashState iniState, double iniQ, double serviceRate, int[] sampleNums, double[] prices, double[] variCostUnits, double[] overheadCosts, double salvageValueUnit, double holdCostUnit, double[][] scenarios, int sampleNum) {
Sampling.resetStartStream();
Sampling sampling = new Sampling();
double[][] samples = sampling.generateLHSamples(distributions, sampleNum);
double[] simuValues = new double[samples.length];
int T = samples[0].length;
int lostSaleCount = 0;
for (int i = 0; i < samples.length; i++) {
CashState state = iniState;
boolean countBeforeBankrupt = false;
boolean countLostBefore = false;
double thisValue = 0;
double optQ = 0;
double thisServiceRate = 1;
for (int t = 0; t < T; t++) {
if (t == 0) {
optQ = iniQ;
thisServiceRate = serviceRate;
}
// integer samples to test sdp
double randomDemand = Math.round(samples[i][t]);
thisValue = state.iniCash + immediateValue.apply(state, optQ, randomDemand);
if (state.getIniInventory() + optQ < randomDemand - 0.1 && countLostBefore == false) {
lostSaleCount++;
countLostBefore = true;
}
if (thisValue < -0.1 && countBeforeBankrupt == false) {
simuValues[i] = 1;
countBeforeBankrupt = true;
}
if (t < T - 1) {
// revise
double thisPeriodServRate = distributions[t].cdf(optQ + state.getIniInventory());
double nextServiceRate = 0;
if (countLostBefore == true)
nextServiceRate = 0;
else {
nextServiceRate = thisPeriodServRate < thisServiceRate ? thisServiceRate : thisServiceRate / thisPeriodServRate;
}
// very important
state = stateTransition.apply(state, optQ, randomDemand);
double iniCash = state.iniCash;
double iniI = state.getIniInventory();
double[] nextPrices = gettTArray(prices, t + 1);
int[] nextSampleNums = gettTArray(sampleNums, t + 1);
double[] nextVariCostUnits = gettTArray(variCostUnits, t + 1);
Distribution[] nexDistributions = gettTArray(distributions, t + 1);
double[] nextOverheadCosts = gettTArray(overheadCosts, t + 1);
double[][] nextScenarios = gettTArray(scenarios, t + 1);
LostSaleChance model = new LostSaleChance(nexDistributions, nextSampleNums, iniCash, iniI, nextPrices, nextVariCostUnits, salvageValueUnit, holdCostUnit, nextOverheadCosts, nextServiceRate, nextScenarios);
double[] result = model.solveSortWhole();
optQ = result[0];
thisServiceRate = nextServiceRate;
}
}
}
int n = samples.length;
double simFinalValue = 1 - Arrays.stream(simuValues).sum() / (double) samples.length;
double sigma = Math.sqrt(simFinalValue * (1 - simFinalValue) / n);
double lowCI = simFinalValue - 1.96 * sigma;
double upCI = simFinalValue + 1.96 * sigma;
double error = 1.96 * sigma;
System.out.printf("the confidence interval for simulated extened SAA sorting whole is [%.4f, %.4f], with error %.4f\n", lowCI, upCI, error);
double lostSaleRate = (double) lostSaleCount / (double) sampleNum;
double[] result = { simFinalValue, lostSaleRate };
return result;
}
use of milp.LostSaleChance in project Stochastic-Inventory by RobinChen121.
the class CashSimulation method simulateSAA2.
/**
* simulate SAA for joint chance problem with another chance updating method.
* @param iniState
* @param iniQ
* @param serviceRate
* @param sampleNums
* @param prices
* @param variCostUnits
* @param overheadCosts
* @param salvageValueUnit
* @param holdCostUnit
* @param scenarios
* @param sampleNum
* @return the final value with lost sale rate
*/
public double[] simulateSAA2(CashState iniState, double iniQ, double serviceRate, int[] sampleNums, double[] prices, double[] variCostUnits, double[] overheadCosts, double salvageValueUnit, double holdCostUnit, double[][] scenarios, int sampleNum) {
Sampling.resetStartStream();
Sampling sampling = new Sampling();
double[][] samples = sampling.generateLHSamples2(distributions, sampleNum);
int maxLostScenarioNum = (int) (sampleNum * (1 - serviceRate));
double[] simuValues = new double[samples.length];
int T = samples[0].length;
CashState[] state = new CashState[samples.length];
Arrays.fill(state, iniState);
double[] optQ = new double[samples.length];
Arrays.fill(optQ, iniQ);
boolean[] countLostBefore = new boolean[samples.length];
boolean[] countBeforeBankrupt = new boolean[samples.length];
int lostSaleCount = 0;
for (int t = 0; t < T; t++) {
double thisValue = 0;
for (int i = 0; i < samples.length; i++) {
double randomDemand = Math.round(samples[i][t]);
if (state[i].getIniInventory() + optQ[i] < randomDemand - 0.1 && countLostBefore[i] == false) {
lostSaleCount++;
countLostBefore[i] = true;
}
thisValue = state[i].iniCash + immediateValue.apply(state[i], optQ[i], randomDemand);
if (thisValue < -0.1 && countBeforeBankrupt[i] == false) {
simuValues[i] = 1;
countBeforeBankrupt[i] = true;
}
state[i] = stateTransition.apply(state[i], optQ[i], randomDemand);
}
double lostRate = (double) (maxLostScenarioNum - lostSaleCount) / (double) (sampleNum - lostSaleCount);
double updateServiceRate = 1 - lostRate;
for (int i = 0; i < samples.length; i++) {
if (t < T - 1) {
// very important
double nextServiceRate = countLostBefore[i] == true ? 0 : updateServiceRate;
double iniCash = state[i].iniCash;
double iniI = state[i].getIniInventory();
double[] nextPrices = gettTArray(prices, t + 1);
int[] nextSampleNums = gettTArray(sampleNums, t + 1);
double[] nextVariCostUnits = gettTArray(variCostUnits, t + 1);
Distribution[] nexDistributions = gettTArray(distributions, t + 1);
double[] nextOverheadCosts = gettTArray(overheadCosts, t + 1);
double[][] nextScenarios = gettTArray(scenarios, t + 1);
LostSaleChance model = new LostSaleChance(nexDistributions, nextSampleNums, iniCash, iniI, nextPrices, nextVariCostUnits, salvageValueUnit, holdCostUnit, nextOverheadCosts, nextServiceRate, nextScenarios);
double[] result = model.solveMaxSurvival();
optQ[i] = result[0];
}
}
}
double simFinalValue = 1 - Arrays.stream(simuValues).sum() / (double) samples.length;
double lostSaleRate = (double) lostSaleCount / (double) sampleNum;
double[] result = { simFinalValue, lostSaleRate };
return result;
}
use of milp.LostSaleChance in project Stochastic-Inventory by RobinChen121.
the class CashSimulation method simulateExtendSAA2.
/**
* simulate extended SAA for another lost sale updating
* @param iniState
* @param iniQ
* @param serviceRate
* @param sampleNums
* @param prices
* @param variCostUnits
* @param overheadCosts
* @param salvageValueUnit
* @param holdCostUnit
* @param scenarios
* @param sampleNum
* @return
*/
public double[] simulateExtendSAA2(CashState iniState, double iniQ, double serviceRate, int[] sampleNums, double[] prices, double[] variCostUnits, double[] overheadCosts, double salvageValueUnit, double holdCostUnit, double[][] scenarios, int sampleNum) {
Sampling.resetStartStream();
Sampling sampling = new Sampling();
double[][] samples = sampling.generateLHSamples2(distributions, sampleNum);
int maxLostScenarioNum = (int) (sampleNum * (1 - serviceRate));
double[] simuValues = new double[samples.length];
int T = samples[0].length;
CashState[] state = new CashState[samples.length];
Arrays.fill(state, iniState);
double[] optQ = new double[samples.length];
Arrays.fill(optQ, iniQ);
boolean[] countLostBefore = new boolean[samples.length];
boolean[] countBeforeBankrupt = new boolean[samples.length];
double[] periodServiceRate = new double[samples.length];
Arrays.fill(periodServiceRate, serviceRate);
int lostSaleCount = 0;
for (int t = 0; t < T; t++) {
double thisValue = 0;
for (int i = 0; i < samples.length; i++) {
double randomDemand = Math.round(samples[i][t]);
if (state[i].getIniInventory() + optQ[i] < randomDemand - 0.1 && countLostBefore[i] == false) {
lostSaleCount++;
countLostBefore[i] = true;
}
thisValue = state[i].iniCash + immediateValue.apply(state[i], optQ[i], randomDemand);
if (thisValue < -0.1 && countBeforeBankrupt[i] == false) {
simuValues[i] = 1;
countBeforeBankrupt[i] = true;
}
state[i] = stateTransition.apply(state[i], optQ[i], randomDemand);
}
double lostRate = (double) (maxLostScenarioNum - lostSaleCount) / (double) (sampleNum - lostSaleCount);
double updateServiceRate = Math.max(serviceRate, 1 - lostRate);
for (int i = 0; i < samples.length; i++) {
if (t < T - 1) {
double thisPeriodServRate = distributions[t].cdf(optQ[i] + state[i].getIniInventory());
periodServiceRate[i] = Math.max(updateServiceRate, thisPeriodServRate);
// updateServiceRate; //very important
double nextServiceRate = countLostBefore[i] == true ? 0 : periodServiceRate[i];
double iniCash = state[i].iniCash;
double iniI = state[i].getIniInventory();
double[] nextPrices = gettTArray(prices, t + 1);
int[] nextSampleNums = gettTArray(sampleNums, t + 1);
double[] nextVariCostUnits = gettTArray(variCostUnits, t + 1);
Distribution[] nexDistributions = gettTArray(distributions, t + 1);
double[] nextOverheadCosts = gettTArray(overheadCosts, t + 1);
double[][] nextScenarios = gettTArray(scenarios, t + 1);
LostSaleChance model = new LostSaleChance(nexDistributions, nextSampleNums, iniCash, iniI, nextPrices, nextVariCostUnits, salvageValueUnit, holdCostUnit, nextOverheadCosts, nextServiceRate, nextScenarios);
double[] result = model.solveSortEach();
optQ[i] = result[0];
}
}
}
double simFinalValue = 1 - Arrays.stream(simuValues).sum() / (double) samples.length;
double lostSaleRate = (double) lostSaleCount / (double) sampleNum;
double[] result = { simFinalValue, lostSaleRate };
return result;
}
Aggregations