我刚开始使用求解器,我仍然不知道我在做什么,但是:
假设我有一个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的差距,但我也不知道如何实现它。