Search in sources :

Example 1 with LognormalDist

use of umontreal.ssj.probdist.LognormalDist 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

Result (com.sun.net.httpserver.Authenticator.Result)1 GRB (gurobi.GRB)1 GRBEnv (gurobi.GRBEnv)1 GRBException (gurobi.GRBException)1 GRBLinExpr (gurobi.GRBLinExpr)1 GRBModel (gurobi.GRBModel)1 GRBVar (gurobi.GRBVar)1 Printable (java.awt.print.Printable)1 BufferedWriter (java.io.BufferedWriter)1 FileWriter (java.io.FileWriter)1 IOException (java.io.IOException)1 DecimalFormat (java.text.DecimalFormat)1 NumberFormat (java.text.NumberFormat)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 List (java.util.List)1 Function (java.util.function.Function)1 IntFunction (java.util.function.IntFunction)1 IntPredicate (java.util.function.IntPredicate)1 Collector (java.util.stream.Collector)1