[英]SAT Solving scheduling problem with Personnel, Skill, Attractionposition and schedule
While I am not new to development, I am very new to SAT solving.虽然我对开发并不陌生,但我对 SAT 解决方案非常陌生。 I have an old codebase solving a schema problem (not using SAT) and I am trying to use google OR tools and a combination of “Employee Scheduling” and “The Job Shop Problem”.
我有一个旧代码库来解决模式问题(不使用 SAT),我正在尝试使用 google OR 工具以及“员工调度”和“工作车间问题”的组合。 Base problem: Each employee has his own schedule for the day.
基本问题:每个员工都有自己的日程安排。 Each day has X attacktions that must be manned For an employee to be allowed to be assigned to an attraction he/she must have the appropiate training.
每天都有 X 次必须有人值守的攻击 为了允许员工被分配到景点,他/她必须接受适当的培训。 Now I have the code for the first two (using C#) but i am struggeling to wrap my head around how to add the last bit to the pussle.
现在我有了前两个的代码(使用 C#),但我正在努力思考如何将最后一位添加到 pussle 中。 This is my code this far:
这是我到目前为止的代码:
Now do I need to extend this with yet one more dimension something like:现在我是否需要将其扩展为另外一个维度,例如:
private CpModel AddExactlyOnePersonToOnePosAndOneTimeslot(int[] personel, int[] timeslots, int[] positions, Dictionary<(int, int), bool> skills, CpModel model, Dictionary<(int, int, int), BoolVar> personelTimePos)
{
List<ILiteral> literals = new List<ILiteral>();
// Add exaktly one employee on each timeslotposition
// Each position is assigned to exactly one personel in the time period.
foreach (var n in personel)
{
foreach (var d in timeslots)
{
foreach (var s in positions)
{
literals.Add(personelTimePos[(n, d, s)]);
}
model.AddExactlyOne(literals);
literals.Clear();
}
}
// One person works at most on one postion during any given timeslot
foreach (var s in positions)
{
foreach (var d in timeslots)
{
foreach (var n in personel)
{
literals.Add(personelTimePos[(n, d, s)]);
}
model.AddAtMostOne(literals);
literals.Clear();
}
}
return model;
}
Now do I need to extend this with yet one more dimension something like:现在我是否需要将其扩展为另外一个维度,例如:
foreach (var s in positions)
{
foreach (var d in timeslots)
{
foreach (var n in personel)
{
foreach(var pp in personSkill)
{
}
}
}
}
Or do I use a new variable something like:或者我是否使用一个新变量,例如:
foreach (var s in positions)
{
foreach (var d in timeslots)
{
foreach (var n in personel)
{
var b = model.NewIntVar(0, 1, $"HasSkill_n{n}d{d}s{s}");
}
}
}
As I said, I am new to SAT solving, but I feel that this must be achievable.正如我所说,我是 SAT 解决的新手,但我觉得这必须是可以实现的。 I just don't know how, I am not trying to have it "solved for me" I am trying to learn by doing.
我只是不知道如何,我不想让它“为我解决”我想边做边学。
Thank you in advance Regards Claes提前谢谢你问候 Claes
*** COMPLETE CODE BELOW *** ***下面的完整代码***
using Google.OrTools.Sat;
namespace Scheduler1
{
public class SmallTest3
{
public class SolutionPrinter : CpSolverSolutionCallback
{
public SolutionPrinter(int[] allPersonel, int[] allTimeSlots, int[] allPos,
Dictionary<(int, int, int), BoolVar> allPersonelTimePos, int limit)
{
solutionCount_ = 0;
personel = allPersonel;
positions = allPos;
timeslots = allTimeSlots;
personelTimePos = allPersonelTimePos;
solutionLimit_ = limit;
}
public override void OnSolutionCallback()
{
Console.WriteLine($"Solution #{solutionCount_}:");
foreach (var pers in personel)
foreach (var time in timeslots)
foreach (var pos in positions)
{
if (Value(personelTimePos[(pers, time, pos)]) != 0)
Console.WriteLine($"Success personel: {pers}, Time {time}, Pos{pos} filling the position");
}
solutionCount_++;
if (solutionCount_ >= solutionLimit_)
{
Console.WriteLine($"Stop search after {solutionLimit_} solutions");
StopSearch();
}
}
public int SolutionCount()
{
return solutionCount_;
}
private int solutionCount_;
int[] personel;
int[] positions;
int[] timeslots;
Dictionary<(int, int, int), BoolVar> personelTimePos;
private int solutionLimit_;
}
private int[] getPersonel(int noPersonel)
{
int personelId = 1000;
var p = Enumerable.Range(0, noPersonel).ToArray();
for (int i = 0; i < p.Length; i++)
{
p[i] = personelId + i;
}
return p;
}
private int[] getPos(int noPos)
{
var p = Enumerable.Range(0, noPos).ToArray();
for (int i = 0; i < p.Length; i++)
{
p[i] = i;
}
return p;
}
private int[] getTimeSlots(int noTimeSlots)
{
var t = Enumerable.Range(0, noTimeSlots).ToArray();
for (int i = 0; i < t.Length; i++)
{
t[i] = i;
}
return t;
}
private Dictionary<(int, int), bool> getSkillForPos(int[] personel, int[] position)
{
Dictionary<(int, int), bool> skill = new Dictionary<(int, int), bool>();
var pi = 0;
var posi = 0;
foreach (var p in personel)
{
foreach (var pos in position)
{
skill.Add((p, pos), false);
posi++;
}
pi++;
}
return skill;
}
public void run()
{
const int personelCnt = 1;
const int positionsCnt = 1;
const int timeslotsCnt = 1;
int[] personel = getPersonel(personelCnt);
int[] positions = getPos(positionsCnt);
int[] timeslots = getTimeSlots(timeslotsCnt);
Dictionary<(int, int), bool> skills = getSkillForPos(personel, positions);
CpModel model = new CpModel();
model.Model.Variables.Capacity = personelCnt * positionsCnt * timeslotsCnt;
var personelTimePos = populateSchedule(personel, timeslots, positions, skills, model);
model = AddExactlyOnePersonToOnePosAndOneTimeslot(personel, timeslots, positions, skills, model, personelTimePos);
CpSolver solver = new CpSolver();
solver.StringParameters += "linearization_level:0 " + "enumerate_all_solutions:true ";
const int solutionLimit = 5;
SolutionPrinter cb = new SolutionPrinter(personel, timeslots, positions, personelTimePos, solutionLimit);
CpSolverStatus status = solver.Solve(model, cb);
Console.WriteLine($"Solve status: {status}");
Console.WriteLine("Statistics");
Console.WriteLine($" conflicts: {solver.NumConflicts()}");
Console.WriteLine($" branches : {solver.NumBranches()}");
Console.WriteLine($" wall time: {solver.WallTime()}s");
}
private Dictionary<(int, int, int), BoolVar> populateSchedule(int[] personel, int[] timeslots, int[] positions, Dictionary<(int, int), bool> skills, CpModel model)
{ // här skapar vi hela arrayen som ska täcka in alla möjliga kombinationer
//Person tid pos
//Janson 12:00 XOP
//Janson 12:15 XOP
//Janson 12:00 FF
//Svenson 12:00 XOP
//
//
Dictionary<(int, int, int), BoolVar> personelTimePos = new Dictionary<(int, int, int), BoolVar>(personel.Count() * positions.Count() * timeslots.Count());
foreach (var n in personel)
foreach (var d in timeslots)
foreach (var s in positions)
{
personelTimePos.Add((n, d, s), model.NewBoolVar($"TimeSlotPositionPersonel_n{n}d{d}s{s}"));
}
return personelTimePos;
}
private CpModel AddExactlyOnePersonToOnePosAndOneTimeslot(int[] personel, int[] timeslots, int[] positions, Dictionary<(int, int), bool> skills, CpModel model, Dictionary<(int, int, int), BoolVar> personelTimePos)
{
List<ILiteral> literals = new List<ILiteral>();
// Add exaktly one employee on each timeslotposition
// Each position is assigned to exactly one personel in the time period.
foreach (var n in personel)
{
foreach (var d in timeslots)
{
foreach (var s in positions)
{
literals.Add(personelTimePos[(n, d, s)]);
}
model.AddExactlyOne(literals);
literals.Clear();
}
}
// One person works at most on one postion during any given timeslot
foreach (var s in positions)
{
foreach (var d in timeslots)
{
foreach (var n in personel)
{
literals.Add(personelTimePos[(n, d, s)]);
}
model.AddAtMostOne(literals);
literals.Clear();
}
}
return model;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.