## ams_version=1.0

Model Main_SingleLevelSmallBucketTwoItems {
    Comment: {
        "Lot sizing
        
        Problem type:
        MIP (small)
        
        Description:
        Lot-sizing problems are production planning problems in which the periods
        are a priori, and production of an item in a given period implies some
        discrete event such as payment of a cost or the loss of a amount of
        production capacity, due to placement of an order, or the set-up, startup,
        or changeover of a machine.
        
        References:
        Problem vpm5 from: Belvaux, G., L.A. Wolsey, Lotsizelib: A library of models
        and matrices for lot-sizing problems, Core discussion paper, Universite
        Catholique de Louvain, 1999."
    }
    Parameter NumberOfItems {
        Definition: 8;
    }
    Parameter NumberOfMachines {
        Definition: 4;
    }
    Parameter NumberOfPeriods {
        Definition: 8;
    }
    Set Items {
        SubsetOf: Integers;
        Index: i;
        Definition: {
            {1..NumberOfItems}
        }
    }
    Set Machines {
        SubsetOf: Integers;
        Index: m;
        Definition: {
            {1..NumberOfMachines}
        }
    }
    Set Periods {
        SubsetOf: Integers;
        Index: t;
        Definition: {
            {1..NumberOfPeriods}
        }
    }
    Parameter InitialStock {
        IndexDomain: (i);
        Definition: data { 1 : 200,  2 : 400,  3 : 600,  4 : 500,  5 : 500,  6 : 400,  7 : 400,  8 : 400 };
    }
    Parameter MinStock {
        IndexDomain: (i);
        Definition: data { 1 : 100,  2 : 200,  3 : 300,  4 : 400,  5 : 200,  6 : 100,  7 : 300,  8 : 200 };
    }
    Parameter MaxStock {
        IndexDomain: (i);
        Definition: data { 1 : 300,  2 : 400,  3 : 400,  4 : 500,  5 : 500,  6 : 600,  7 : 400,  8 : 300 };
    }
    Parameter ProductionRate {
        IndexDomain: (i,m);
    }
    Parameter MachineStartUpTime {
        IndexDomain: (m);
        Definition: data { 1 : 0.100,  2 : 0.200,  3 : 0.400,  4 : 0.500 };
    }
    Parameter StartUpTime {
        IndexDomain: (i,m);
        Definition: MachineStartUpTime(m);
    }
    Parameter Demand {
        IndexDomain: (i,t);
    }
    Variable X {
        IndexDomain: (i,m,t);
        Range: nonnegative;
        Comment: "Fraction produced of item i on machine m in period t";
    }
    Variable Y {
        IndexDomain: (i,m,t);
        Range: binary;
        Comment: "Production variable: 1 if item i is produced on machine m in period t";
    }
    Variable S {
        IndexDomain: (i,t);
        Range: nonnegative;
        Comment: "Stock of item i in period t";
    }
    Variable Z {
        IndexDomain: (i,t,m);
        Range: binary;
        Comment: "Startup variable: 1 if production of item i is started on machine m in period t";
    }
    Variable V {
        IndexDomain: (i);
        Range: nonnegative;
        Comment: "Excess over upper bound on stock for item i";
    }
    Variable TimeLoss {
        Range: free;
        Definition: sum((i,m,t), StartUpTime(i,m) * Z(i, t, m)) + sum(i, 10 * V(i));
    }
    Constraint FlowConstraint {
        IndexDomain: (i,t) | t>1;
        Definition: S(i, t-1) + sum(m, ProductionRate(i, m) * X(i, m, t)) = Demand(i, t) + S(i, t);
    }
    Constraint FlowConstraintBis {
        IndexDomain: (i);
        Definition: InitialStock(i) + sum(m, ProductionRate(i, m) * X(i, m, 1)) = Demand(i, 1) + S(i, 1);
    }
    Constraint StartUpContraint {
        IndexDomain: (i,m,t);
        Definition: X(i, m, t) + StartUpTime(i,m) * Z(i, t, m) <= Y(i, m, t);
    }
    Constraint StartUpConstraint1 {
        IndexDomain: (i,m,t);
        Definition: Z(i, t, m) >= Y(i, m, t) - Y(i, m, t-1);
    }
    Constraint StartUpConstraint2 {
        IndexDomain: (i,t,m);
        Definition: Z(i, t, m) + Z(i, t-1, m) <= Y(i, m, t);
    }
    Constraint StartUpConstraint3 {
        IndexDomain: (m,t);
        Definition: sum(i, Y(i, m, t) - Z(i, t, m)) <= 1;
    }
    Constraint UniqueStartUpConstraint {
        IndexDomain: (m,t);
        Definition: sum(i, Z(i, t, m)) <= 1;
    }
    Constraint StartUpTimeConstraint {
        IndexDomain: (m,t);
        Definition: sum(i, X(i, m, t)) + sum(i, StartUpTime(i, m) * Z(i, t, m)) <= 1;
    }
    Constraint MaxStockConstraint {
        IndexDomain: (i,t);
        Definition: S(i, t) <= MaxStock(i) + V(i);
    }
    Constraint MinStockConstraint {
        IndexDomain: (i,t);
        Definition: S(i, t) >= MinStock(i);
    }
    MathematicalProgram LeastTime {
        Objective: TimeLoss;
        Direction: minimize;
        Constraints: AllConstraints;
        Variables: AllVariables;
        Type: Automatic;
    }
    Procedure MainInitialization {
        Body: {
            Demand(i,t) := DATA TABLE
            
               1      2      3      4      5      6      7      8
            !
            1 400    300    300     0      0    600      0      0
            2   0    300    200   300    400      0      0      0
            3   0      0      0   500    600      0      0      0
            4   0      0      0     0    300    800      0      0
            5   0      0      0   500      0    100      0      0
            6   0      0      0     0      0      0    900    200
            7 700    200      0     0      0      0      0      0
            8   0    400    500     0      0      0      0      0
            ;
            
            
            ProductionRate(i,m) := DATA TABLE
            
                1       2       3       4
            !
            1  200     300     400     300
            2  400     200     100     400
            3  400     400     300     400
            4  300     400     200     300
            5  200     200     100     300
            6  300     200     400     500
            7  300     500     600     600
            8  500     500     400     600
            ;
        }
    }
    Procedure MainExecution {
        Body: {
            solve LeastTime;
        }
    }
    Procedure MainTermination {
        Body: {
            return 1;
        }
    }
}