Search in sources :

Example 1 with CashSimulation

use of sdp.cash.CashSimulation 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]);
}
Also used : IntStream(java.util.stream.IntStream) ImmediateValueFunction(sdp.inventory.ImmediateValue.ImmediateValueFunction) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) CashSimulation(sdp.cash.CashSimulation) CashRecursion(sdp.cash.CashRecursion) DecimalFormat(java.text.DecimalFormat) OptDirection(sdp.cash.CashRecursion.OptDirection) CashState(sdp.cash.CashState) Function(java.util.function.Function) StateTransitionFunction(sdp.inventory.StateTransition.StateTransitionFunction) DoubleStream(java.util.stream.DoubleStream) GetPmf(sdp.inventory.GetPmf) PoissonDist(umontreal.ssj.probdist.PoissonDist) Distribution(umontreal.ssj.probdist.Distribution) CashSimulation(sdp.cash.CashSimulation) PoissonDist(umontreal.ssj.probdist.PoissonDist) DecimalFormat(java.text.DecimalFormat) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) CashRecursion(sdp.cash.CashRecursion) Distribution(umontreal.ssj.probdist.Distribution) CashState(sdp.cash.CashState) GetPmf(sdp.inventory.GetPmf)

Example 2 with CashSimulation

use of sdp.cash.CashSimulation 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();
// 
}
Also used : IntStream(java.util.stream.IntStream) ImmediateValueFunction(sdp.inventory.ImmediateValue.ImmediateValueFunction) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) CashSimulation(sdp.cash.CashSimulation) Arrays(java.util.Arrays) DiscreteDistribution(umontreal.ssj.probdist.DiscreteDistribution) WriteToCsv(sdp.write.WriteToCsv) CashRecursion(sdp.cash.CashRecursion) OptDirection(sdp.cash.CashRecursion.OptDirection) MipCashConstraint(milp.MipCashConstraint) CashState(sdp.cash.CashState) NormalDist(umontreal.ssj.probdist.NormalDist) Function(java.util.function.Function) StateTransitionFunction(sdp.inventory.StateTransition.StateTransitionFunction) ArrayList(java.util.ArrayList) DoubleStream(java.util.stream.DoubleStream) GetPmf(sdp.inventory.GetPmf) CheckKConvexity(sdp.inventory.CheckKConvexity) TreeMap(java.util.TreeMap) Map(java.util.Map) State(sdp.inventory.State) PoissonDist(umontreal.ssj.probdist.PoissonDist) Drawing(sdp.inventory.Drawing) Distribution(umontreal.ssj.probdist.Distribution) CashSimulation(sdp.cash.CashSimulation) PoissonDist(umontreal.ssj.probdist.PoissonDist) MipCashConstraint(milp.MipCashConstraint) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) CashRecursion(sdp.cash.CashRecursion) DiscreteDistribution(umontreal.ssj.probdist.DiscreteDistribution) Distribution(umontreal.ssj.probdist.Distribution) CashState(sdp.cash.CashState) GetPmf(sdp.inventory.GetPmf)

Example 3 with CashSimulation

use of sdp.cash.CashSimulation 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);
}
Also used : IntStream(java.util.stream.IntStream) ImmediateValueFunction(sdp.inventory.ImmediateValue.ImmediateValueFunction) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) CashSimulation(sdp.cash.CashSimulation) DiscreteDistribution(umontreal.ssj.probdist.DiscreteDistribution) WriteToCsv(sdp.write.WriteToCsv) CashRecursion(sdp.cash.CashRecursion) OptDirection(sdp.cash.CashRecursion.OptDirection) CashState(sdp.cash.CashState) Function(java.util.function.Function) StateTransitionFunction(sdp.inventory.StateTransition.StateTransitionFunction) DoubleStream(java.util.stream.DoubleStream) GetPmf(sdp.inventory.GetPmf) CheckKConvexity(sdp.inventory.CheckKConvexity) TreeMap(java.util.TreeMap) Map(java.util.Map) State(sdp.inventory.State) WriteToExcel(sdp.write.WriteToExcel) PoissonDist(umontreal.ssj.probdist.PoissonDist) Drawing(sdp.inventory.Drawing) Distribution(umontreal.ssj.probdist.Distribution) CashSimulation(sdp.cash.CashSimulation) Drawing(sdp.inventory.Drawing) WriteToCsv(sdp.write.WriteToCsv) CashRecursion(sdp.cash.CashRecursion) CashState(sdp.cash.CashState) GetPmf(sdp.inventory.GetPmf) PoissonDist(umontreal.ssj.probdist.PoissonDist) TreeMap(java.util.TreeMap) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) CashState(sdp.cash.CashState) State(sdp.inventory.State) DiscreteDistribution(umontreal.ssj.probdist.DiscreteDistribution) Distribution(umontreal.ssj.probdist.Distribution)

Example 4 with CashSimulation

use of sdp.cash.CashSimulation in project Stochastic-Inventory by RobinChen121.

the class CashConstraintLookPolicy method main.

public static void main(String[] args) {
    double[] meanDemand = { 2, 3, 8 };
    // double[] meanDemand = {20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
    double iniInventory = 8;
    double iniCash = 100;
    double fixOrderCost = 10;
    double variCost = 1;
    double price = 8;
    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 = 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 = -100;
    double maxCashState = 2000;
    double discountFactor = 1;
    double xmin = 0;
    double xmax = 10;
    double Rmin = fixOrderCost;
    double Rmax = 40;
    int row = 0;
    int column = 0;
    int columnNum = (int) (Rmax - Rmin + 1) + 1;
    // ((Rmax - Rmin + 1)/2) + 2;
    int rowNum = (int) ((xmax - xmin + 1) / 1) + 1;
    double[][] resultTable = new double[rowNum][columnNum];
    for (iniInventory = xmax; iniInventory >= xmin; iniInventory--) {
        column = 0;
        for (iniCash = Rmin; iniCash <= Rmax; iniCash = iniCash + 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 = price * 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;
                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 = iniCash + recursion.getExpectedValue(initialState);
            System.out.println("final optimal cash  is " + finalValue);
            double optQ = recursion.getAction(initialState);
            System.out.println("optimal order quantity in the first priod is : " + optQ);
            double time = (System.currentTimeMillis() - currTime) / 1000;
            System.out.println("running time is " + time + "s");
            System.out.println("initial inventory is " + iniInventory);
            System.out.println("initial cash is " + iniCash);
            resultTable[0][column + 1] = iniCash;
            resultTable[row + 1][0] = iniInventory;
            // finalValue - iniCash;
            resultTable[row + 1][column + 1] = optQ;
            System.out.println("**********************************************************");
            // /*******************************************************************
            // * Simulating sdp results
            // * parameter vales like price, variCost, holdingCost etc.
            // * are only for compute L(y), not very necessary
            // */
            // int sampleNum = 10000;
            // 
            // CashSimulation simuation = new CashSimulation(distributions, sampleNum, recursion, discountFactor,
            // fixOrderCost, price, variCost, holdingCost, salvageValue); // no need to add overheadCost in this class
            // double simFinalValue = simuation.simulateSDPGivenSamplNum(initialState);
            // double error = 0.0001;
            // double confidence = 0.95;
            // simuation.simulateSDPwithErrorConfidence(initialState, error, confidence);
            // 
            column++;
        }
        row++;
    }
    WriteToExcel wr = new WriteToExcel();
    wr.writeArrayToExcel(resultTable, "resultTable.xls");
}
Also used : IntStream(java.util.stream.IntStream) ImmediateValueFunction(sdp.inventory.ImmediateValue.ImmediateValueFunction) CashSimulation(sdp.cash.CashSimulation) Arrays(java.util.Arrays) DiscreteDistribution(umontreal.ssj.probdist.DiscreteDistribution) CashRecursion(sdp.cash.CashRecursion) OptDirection(sdp.cash.CashRecursion.OptDirection) MipCashConstraint(milp.MipCashConstraint) CashState(sdp.cash.CashState) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Map(java.util.Map) State(sdp.inventory.State) WriteToExcel(sdp.write.WriteToExcel) PoissonDist(umontreal.ssj.probdist.PoissonDist) Drawing(sdp.inventory.Drawing) Distribution(umontreal.ssj.probdist.Distribution) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) WriteToCsv(sdp.write.WriteToCsv) NormalDist(umontreal.ssj.probdist.NormalDist) StateTransitionFunction(sdp.inventory.StateTransition.StateTransitionFunction) DoubleStream(java.util.stream.DoubleStream) GetPmf(sdp.inventory.GetPmf) CheckKConvexity(sdp.inventory.CheckKConvexity) TreeMap(java.util.TreeMap) PoissonDist(umontreal.ssj.probdist.PoissonDist) MipCashConstraint(milp.MipCashConstraint) FindCCrieria(cash.strongconstraint.FindsCS.FindCCrieria) CashRecursion(sdp.cash.CashRecursion) WriteToExcel(sdp.write.WriteToExcel) DiscreteDistribution(umontreal.ssj.probdist.DiscreteDistribution) Distribution(umontreal.ssj.probdist.Distribution) CashState(sdp.cash.CashState) GetPmf(sdp.inventory.GetPmf)

Example 5 with CashSimulation

use of sdp.cash.CashSimulation 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]));
}
Also used : IntStream(java.util.stream.IntStream) ImmediateValueFunction(sdp.inventory.ImmediateValue.ImmediateValueFunction) CashSimulation(sdp.cash.CashSimulation) Arrays(java.util.Arrays) GRBException(gurobi.GRBException) CashRecursion(sdp.cash.CashRecursion) OptDirection(sdp.cash.CashRecursion.OptDirection) CashState(sdp.cash.CashState) Function(java.util.function.Function) IntPredicate(java.util.function.IntPredicate) NumberFormat(java.text.NumberFormat) ArrayList(java.util.ArrayList) GRBModel(gurobi.GRBModel) PositiveCashChance(milp.PositiveCashChance) Printable(java.awt.print.Printable) Collector(java.util.stream.Collector) Result(com.sun.net.httpserver.Authenticator.Result) PoissonDist(umontreal.ssj.probdist.PoissonDist) Distribution(umontreal.ssj.probdist.Distribution) IntFunction(java.util.function.IntFunction) LostSaleChance(milp.LostSaleChance) GRBVar(gurobi.GRBVar) SimulateChanceCash(milp.SimulateChanceCash) BufferedWriter(java.io.BufferedWriter) GRBLinExpr(gurobi.GRBLinExpr) FileWriter(java.io.FileWriter) DecimalFormat(java.text.DecimalFormat) NormalDist(umontreal.ssj.probdist.NormalDist) IOException(java.io.IOException) LognormalDist(umontreal.ssj.probdist.LognormalDist) Sampling(sdp.sampling.Sampling) Collectors(java.util.stream.Collectors) StateTransitionFunction(sdp.inventory.StateTransition.StateTransitionFunction) DoubleStream(java.util.stream.DoubleStream) GetPmf(sdp.inventory.GetPmf) List(java.util.List) CartesianProduct(sdp.sampling.CartesianProduct) GRBEnv(gurobi.GRBEnv) GRB(gurobi.GRB) CashSimulation(sdp.cash.CashSimulation) PoissonDist(umontreal.ssj.probdist.PoissonDist) DecimalFormat(java.text.DecimalFormat) CashRecursion(sdp.cash.CashRecursion) Distribution(umontreal.ssj.probdist.Distribution) CashState(sdp.cash.CashState) LostSaleChance(milp.LostSaleChance) Sampling(sdp.sampling.Sampling) GetPmf(sdp.inventory.GetPmf) NumberFormat(java.text.NumberFormat)

Aggregations

CashSimulation (sdp.cash.CashSimulation)13 CashState (sdp.cash.CashState)13 ImmediateValueFunction (sdp.inventory.ImmediateValue.ImmediateValueFunction)13 StateTransitionFunction (sdp.inventory.StateTransition.StateTransitionFunction)13 PoissonDist (umontreal.ssj.probdist.PoissonDist)13 GetPmf (sdp.inventory.GetPmf)12 Function (java.util.function.Function)11 CashRecursion (sdp.cash.CashRecursion)11 Distribution (umontreal.ssj.probdist.Distribution)11 IntStream (java.util.stream.IntStream)10 DoubleStream (java.util.stream.DoubleStream)9 OptDirection (sdp.cash.CashRecursion.OptDirection)9 Map (java.util.Map)7 TreeMap (java.util.TreeMap)7 FindCCrieria (cash.strongconstraint.FindsCS.FindCCrieria)6 Arrays (java.util.Arrays)6 MipCashConstraint (milp.MipCashConstraint)5 State (sdp.inventory.State)5 ArrayList (java.util.ArrayList)4 WriteToCsv (sdp.write.WriteToCsv)4