Example #1
0
        private PeriodInformation GetPredecessor(PeriodInformation currentPeriod)
        {
            if (currentPeriod.Period <= 1)
            {
                throw new InvalidOperationException($"There is no period before T={currentPeriod.Period}.");
            }

            // make query fail/throw if data is not correct.
            return(this.PeriodInformation.Single(p => p.Period == currentPeriod.Period - 1));
        }
Example #2
0
        /// <summary>
        /// Initializes a new instance of the
        /// <see cref="CapacitatedLotsizingModel"/> class and initializes all fields
        /// </summary>
        /// <param name="timesteps">
        /// The time steps of the problem
        /// </param>
        public CapacitatedLotsizingModel(IEnumerable <PeriodInformation> timesteps)
        {
            this.PeriodInformation = timesteps.ToList();
            this.Model             = new Model();

            // Binary indicator variables
            this.y = new VariableCollection <PeriodInformation>(
                this.Model,
                this.PeriodInformation,
                "y",
                timestep => $"machines_active_in_period_{timestep.Period}",
                timestep => 0,
                timestep => 1,
                VariableType.Binary);

            // Continuous production variables
            this.x = new VariableCollection <PeriodInformation>(
                this.Model,
                this.PeriodInformation,
                "x",
                timestep => $"produced_amount_period_{timestep.Period}",
                timestep => 0,
                timestep => timestep.Capacity,
                VariableType.Continuous);

            // Continuous inventory variables
            this.s = new VariableCollection <PeriodInformation>(
                this.Model,
                this.PeriodInformation,
                "s",
                timestep => $"storage_end_of_period_{timestep.Period}",
                timestep => 0,
                // The maximum storage content is limited by the cumulative production.
                // Since we need to fulfill demands from 'some' previous production,
                // the maximum available stock amount can be reduced by the occuring demands.
                timestep => this.ComputeStorageVariableUpperBound(timestep),
                VariableType.Continuous);

            // Create constraints

            // flow balance: 'input == output'
            // input: previous storage + production
            // output: outgoing storage + demand
            foreach (var periodInformation in this.PeriodInformation)
            {
                var flowBalanceExpression = this.x[periodInformation] - this.s[periodInformation] - periodInformation.Demand;

                // 'previous storage' only exists after the initial period
                if (periodInformation.Period > 1)
                {
                    var previousPeriodInformation = this.GetPredecessor(periodInformation);
                    flowBalanceExpression += this.s[previousPeriodInformation];
                }
                this.Model.AddConstraint(
                    flowBalanceExpression == 0,
                    $"flow_balance_{periodInformation.Period}");
            }

            // Final inventory needs to be 0
            var last = PeriodInformation.Last();

            this.Model.AddConstraint(
                this.s[last] == 0,
                $"final_storage");

            // Production volume 'x' of a time step can not be larger than the capacity
            foreach (var periodInfo in this.PeriodInformation)
            {
                this.Model.AddConstraint(
                    this.x[periodInfo] <= periodInfo.Capacity * this.y[periodInfo],
                    $"production_capacity_{periodInfo}");
            }


            // Add the objective:
            // Sum of the setup, production and inventory costs for all time steps
            // \sum_{time step in Time steps} \{ x_{time step} * SetupCost_{time step} +
            //                                 y_{time step} * ProductionCost_{time step} +
            //                                 s_{time step} * InventoryCost_{time step} \}
            this.Model.AddObjective(
                new Objective(Expression.Sum(this.PeriodInformation.Select
                                                 (timestep => (y[timestep] * timestep.SetupCost +
                                                               x[timestep] * timestep.ProductionCost +
                                                               s[timestep] * timestep.InventoryCost))),
                              "totalCost",
                              ObjectiveSense.Minimize)
                );
        }
Example #3
0
 private double ComputeStorageVariableUpperBound(PeriodInformation currentPeriod)
 {
     // we cannot store more than 'theoretical production limit' - 'required amount' (=demand)
     return(this.PeriodInformation.Where(pi => pi.Period <= currentPeriod.Period)
            .Sum(pi => pi.Capacity - pi.Demand));
 }