Microsoft Foundation Solver:作业车间计划问题

时间:2018-02-25 14:08:40

标签: c# .net mathematical-optimization nonlinear-optimization ms-solver-foundation

我刚开始使用求解器,我仍然不知道我在做什么,但是:

假设我有一个JOB Shop Schedulling问题,我已经按照教程进行了一些有效的解决方案,现在我正在努力扩展这个:

我有一组要在X资源(机器)上完成的任务,我想在其中创建一个计划 a)任务尽快完成 b)我希望尽量减少考虑Type开关所需的时间。

同一台机器可以做不同的处理不同类型的任务,但是当切换类型时,机器需要设置1小时,但我不知道如何处理这个约束,这就是什么我从教程中得到了。

  private void InitializeGoal()
        {
            Goal goal = model.AddGoal("goal", GoalKind.Minimize, makespan); // (34)

        }

        /// <summary>Create the model.
        /// </summary>
        /// <param name="project">The project to be scheduled.</param>
        public void Initialize(Project project)
        {
            context = SolverContext.GetContext();
            context.ClearModel();
            model = context.CreateModel();

            int eventCount = project.Tasks.Count;

            // we will fill these in in the remainder of the post.
            InitializeSets(project.Tasks.Count, eventCount, project.Resources.Count);
            InitializeParameters(project.Tasks, project.Resources);
            InitializeDecisions();
            InitializeGoal();
            InitializeConstraints(project, eventCount);
        }

        private void InitializeSets(int taskCount, int eventCount, int resourceCount)
        {
            tasks = new Set(Domain.Real, "tasks");
            events = new Set(0, eventCount, 1);
            events1ToN = new Set(1, eventCount, 1); // starting from event 1.
        }

        private void InitializeParameters(ICollection<Task> t, ICollection<Resource> r)
        {
            entrega = new Parameter(Domain.Integer, "entrega", tasks);
            entrega.SetBinding(t, "Entrega", "ID");
            molde = new Parameter(Domain.Integer, "molde", tasks);
            molde.SetBinding(t, "Molde", "ID");
            duration = new Parameter(Domain.RealNonnegative, "duration", tasks);
            duration.SetBinding(t, "Duration", "ID");
            model.AddParameters(duration,molde,entrega);
        }

        private void InitializeDecisions()
        {
            makespan = new Decision(Domain.RealNonnegative, "makespan");
            isActive = new Decision(Domain.IntegerRange(0, 1), "isActive", tasks, events);
            start = new Decision(Domain.RealNonnegative, "start", events);

            modelSwitch = new Decision(Domain.Boolean, "modelSwitch", tasks);

            model.AddDecisions(makespan, isActive, start, modelSwitch);
        }

        private void InitializeConstraints(Project project, int eventCount)
        {
            // Establish the makespan: the maximum finish time over all activities.
            model.AddConstraint("c35",
              Model.ForEach(events1ToN, e =>
                Model.ForEach(tasks, i =>
                  makespan >= start[e] + (isActive[i, e] - isActive[i, e - 1]) * duration[i] )
            ));

            model.AddConstraint("ValidDeliveryDate",
            Model.ForEach(tasks, e => start[e] +  duration[e] <= entrega[e]));


            // The first event starts at time 0.
            model.AddConstraint("c_36", start[0] == 0);
            // Link the isActive decision to the starts of each event and task durations.
            model.AddConstraint("c_37",
              Model.ForEach(events1ToN, e =>
                Model.ForEachWhere(events, f =>
                  Model.ForEach(tasks, i =>
                    start[f] >= start[e] + ((isActive[i, e] - isActive[i, e - 1]) - (isActive[i, f] - isActive[i, f - 1]) - 1) * duration[i]
                    ), f => f > e)));

            // Link the isActive decision with the first event. This constraint is missing in the original
            // paper.
            model.AddConstraint("c_37_e0",
              Model.ForEach(events1ToN, f =>
                Model.ForEach(tasks, i =>
                  start[f] >= start[0] + (isActive[i, 0] - (isActive[i, f] - isActive[i, f - 1]) - 1) * duration[i]
              )));

            // Order the events.
            model.AddConstraint("c_38", Model.ForEach(events1ToN, e => start[e] >= start[e - 1]));

            // Ensure adjacency of events for an in-progress task.
            SumTermBuilder sum = new SumTermBuilder(eventCount);
            for (int i = 0; i < project.Tasks.Count; i++)
            {
                for (int e = 1; e < eventCount; e++)
                {
                    sum.Add(isActive[i, e - 1]);
                    model.AddConstraint("c_39_" + i + "_" + e,
                      sum.ToTerm() <= e * (1 - (isActive[i, e] - isActive[i, e - 1])));
                }
                sum.Clear();
            }

            sum = new SumTermBuilder(eventCount);
            for (int i = 0; i < project.Tasks.Count; i++)
            {
                for (int e = 1; e < eventCount; e++)
                {
                    for (int e1 = e; e1 < eventCount; e1++)
                    {
                        sum.Add(isActive[i, e1]); // (it's inefficient to reconstruct this for each value of e.)
                    }
                    model.AddConstraint("c_40_" + i + "_" + e,
                      sum.ToTerm() <= e * (1 + (isActive[i, e] - isActive[i, e - 1])));
                    sum.Clear();
                }
            }

            // All activities must be active during the project.
            model.AddConstraint("c_41", Model.ForEach(tasks, i =>
              Model.Sum(Model.ForEach(events, e => isActive[i, e])) >= 1));

            // A link (i, j) means that the start of task j must be after the finish of task i.
            int c42 = 0;
            foreach (TaskDependency link in project.Dependencies)
            {
                int i = link.Source.ID;
                int j = link.Destination.ID;
                sum = new SumTermBuilder(eventCount);
                for (int e = 0; e < eventCount; e++)
                {
                    sum.Add(isActive[j, e]); // sum now has isActive[j, 0] .. isActive[j, e].
                    model.AddConstraint("c_42_" + c42++, isActive[i, e] + sum.ToTerm() <= 1 + e * (1 - isActive[i, e]));
                }
            }

            // Resource usage during each event must not exceed resource capacity.
            Dictionary<Resource, int> resToId = new Dictionary<Resource, int>(project.Resources.Count);
            for (int k = 0; k < project.Resources.Count; k++)
            {
                resToId[project.Resources[k]] = k;
            }
            SumTermBuilder[] totalResWork = new SumTermBuilder[project.Resources.Count];
            int c43 = 0;
            for (int e = 0; e < eventCount; e++)
            {
                for (int taskID = 0; taskID < project.Tasks.Count; taskID++)
                {
                    foreach (var assn in project.Tasks[taskID].Assignments)
                    {
                        int resID = resToId[assn.Resource];
                        if (totalResWork[resID] == null)
                        {
                            totalResWork[resID] = new SumTermBuilder(5); // most tasks will have <= 4 assignments.
                        }
                        totalResWork[resID].Add(assn.Units * isActive[taskID, e]);
                    }
                }

                for (int resID = 0; resID < totalResWork.Length; resID++)
                {
                    if (totalResWork[resID] != null)
                    {
                        model.AddConstraint("c43_" + c43++, totalResWork[resID].ToTerm() <= project.Resources[resID].MaxUnits);
                        totalResWork[resID] = null; // note: memory churn...
                    }
                }
            }
        }

我添加了约束以验证任务在交付数据之前完成(在这种情况下为entrega):

    model.AddConstraint("ValidDeliveryDate",
    Model.ForEach(tasks, e => start[e] +  duration[e] <= entrega[e]));

这似乎可以正常工作,但现在我想考虑Molde(Aka类型)的任务,基本上,我想减少任务类型之间的切换次数和完成此任务所需的时间。 / p>

我认为最快的方法是更改​​任务持续时间以适应切换时间,但我对如何/在何处进行操作毫无头绪。

我对所有这些求解器/优化问题都非常感兴趣,但是项目出现在这可能有用的地方,所以非常感谢任何见解/解释。

编辑:我想到了一个可能的解决方案,即添加一个约束,强制执行两个连续任务,如果Molde变量改变了1h的差距,但我也不知道如何实现它。

0 个答案:

没有答案