简体   繁体   English

SAT解决人员、技能、景点位置和日程安排问题

[英]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;
        }

    }

}

Have you looked at the complex shift scheduling example?您看过复杂的班次安排示例吗?

It is located here .它位于这里 It is an adaptation of the original example in python located here .它是对位于此处的 python 中原始示例的改编。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM