/// <summary> /// Assign the shifts as is from the constrains /// Can cause conflicts in schedulare /// </summary> /// <param name="schedulare"></param> /// <param name="shiftsContainer"></param> private static void InitialTheSchedular(Schedulare schedulare, ShiftsContainer shiftsContainer) { foreach (var emp in shiftsContainer.EmployeeConstraints) { var currEmpName = new Worker() { Name = emp.Name }; foreach (var empDayConstraint in emp.WeeklyConstraints) { if (empDayConstraint.Value.Contains("Free day")) { continue; } var constraintsDay = empDayConstraint.Key; var constraintsShift = empDayConstraint.Value; var schedulareDay = schedulare.Days.FirstOrDefault(x => x.Name.Contains(constraintsDay)); var schedulareShift = schedulareDay.Shifts.FirstOrDefault(x => x.Name.Contains(constraintsShift)); schedulareShift.Workers.Add(currEmpName); } } }
protected SchedulareState GetSchedulareState(Schedulare schedulare, ShiftsContainer shiftsContainer, TreeNode <Schedulare> treeNode = null) { var weight = 0; // if workers have 2 shifts in the row +10 TwoShiftsInARowWeight(schedulare, shiftsContainer, ref weight); // if worker did not got the shift he asked for +20 LackSatisfactionConstraintsWeight(schedulare, shiftsContainer, ref weight); // if worker have 5 work days in the row +20 var shiftsInARow = 3; ShiftsInARow(schedulare, shiftsContainer, ref weight, shiftsInARow); // if worker got shift that he did not asked +20 UnwantedShift(schedulare, shiftsContainer, ref weight); // if worker assinghned twice on the same shift TwiceOnTheSameShift(schedulare, shiftsContainer, ref weight); return(new SchedulareState() { Node = treeNode, Weight = weight }); }
private void ValidateInitialStep(Schedulare schedulare, ShiftsContainer shiftsContainer) { var validNumberOfWorkersInShift = shiftsContainer.ShiftParams.NumberOfWokersInShift; foreach (var day in schedulare.Days) { foreach (var shift in day.Shifts) { if (validNumberOfWorkersInShift >= shift.Workers.Count()) { continue; } var randList = GetListOfRandomNumber(shift.Workers.Count()); List <int> fortuneWorkerIndexList = GetFortuneWorkerIndexList(validNumberOfWorkersInShift, randList); List <Worker> fortuneWorkerList = InitializeFortuneWorkers(shift, fortuneWorkerIndexList); var names = fortuneWorkerList.Select(x => x.Name).ToList(); var workersThatWereRemoved = shift.Workers.Where(x => !names.Any(y => y.CompareContent(x.Name))).ToList(); //add workers what was not lucky to the back log _workersBackLog.AddRange(workersThatWereRemoved); shift.Workers = fortuneWorkerList; } } }
public override SchedulareState Execute(Schedulare schedulare, ShiftsContainer shiftsContainer) { _schedulare = schedulare; _shiftsContainer = shiftsContainer; _executeStopwatch.Start(); _workersBackLog = new List <Worker>(); _unresolvedShifts = new List <Day>(); // step 1 init with all the constrains InitialTheSchedular(schedulare, shiftsContainer); // step 2 validate shifts ValidateInitialStep(schedulare, shiftsContainer); // step 3 resolve conflicts from previous step ResolveAndFillTheSchdulare(schedulare, shiftsContainer); var executionTime = _executeStopwatch.Elapsed.TotalSeconds; _executeStopwatch.Reset(); var schedulareState = GetSchedulareState(schedulare, shiftsContainer, new TreeNode <Schedulare>(schedulare)); schedulareState.ExecuteTime = executionTime; return(schedulareState); }
private SchedulareState RunRandAlgo(ShiftsContainer shiftsContainer, Schedulare schedulare) { var randAlgo = _factory.GetAlgo("Rand"); var randResult = randAlgo.Execute(schedulare.DeepClone(), shiftsContainer); PrintDebugData(shiftsContainer, randResult, randAlgo.ToString()); UpdateSchefulareStatistics(shiftsContainer, randResult, randAlgo.ToString()); return(randResult); }
private void InitParams(Schedulare schedulare, ShiftsContainer shiftsContainer) { ShiftsContainer = shiftsContainer; OpenSet = new SortedArray <SchedulareState>(new SchedulareComparerArray()); TreeRoot = new TreeNode <Schedulare>(schedulare); CloseSet = new SortedArray <SchedulareState>(new SchedulareComparerArray()); }
private void InitParams(Schedulare schedulare, ShiftsContainer shiftsContainer) { ShiftsContainer = shiftsContainer; CloseSet = new IntervalHeap <SchedulareState>(new SchedulareComparer()); OpenSet = new IntervalHeap <SchedulareState>(new SchedulareComparer()); TreeRoot = new TreeNode <Schedulare>(schedulare); }
private void InitParams(Schedulare schedulare, ShiftsContainer shiftsContainer) { ShiftsContainer = shiftsContainer; TreeRoot = new TreeNode <Schedulare>(schedulare); CloseSet = new CircularList(20); OpenSet = new IntervalHeap <SchedulareState>(new SchedulareComparer()); ExplorationStopwatch = new Stopwatch(); }
private void RunHuristicMethods() { var shiftsContainer = _constructsShift.Excute(); var schedulare = new Schedulare(shiftsContainer); var randResult = RunRandAlgo(shiftsContainer, schedulare); foreach (var algo in _factory.GetAll()) { RunAlgo(shiftsContainer, schedulare, randResult, algo); } }
private void AssignRandomEmployee(Schedulare schedulare, Day schedulareDay, Shift schedulareShift) { Func <Schedulare, Day, Shift, bool, bool> action = TryOrAssignEmployee; var isAssined = CommonLogic.TryWithRetries(20, () => TryOrAssignEmployee(schedulare, schedulareDay, schedulareShift)); if (!isAssined) // failed to fill current shift 'schedulareShift' { TryOrAssignEmployee(schedulare, schedulareDay, schedulareShift, false); _unresolvedShifts.Add(new Day() { Name = schedulareDay.Name, Shifts = schedulareDay.Shifts.Where(x => x.Name.CompareContent(schedulareShift.Name)).ToList() }); } }
private List <DayShift> GetShiftList(Schedulare value) { var shiftsList = value.Days.SelectMany(x => x.Shifts).ToList(); var list = new List <DayShift>(); foreach (var day in value.Days) { foreach (var shift in day.Shifts) { list.Add(new DayShift() { DayName = day.Name, Shift = shift }); } } return(list); }
protected int UnwantedShift(Schedulare schedulare, ShiftsContainer shiftsContainer, ref int weight) { try { foreach (var employee in shiftsContainer.EmployeeConstraints) { var currEmpConstraints = employee.WeeklyConstraints.Where(x => !x.Value.ContainsContent("Free day")).ToList(); foreach (var day in schedulare.Days) { foreach (var shift in day.Shifts) { if (!shift.Workers.Any(x => x.Name.CompareContent(employee.Name))) { continue; } var constraintDay = currEmpConstraints.FirstOrDefault(x => x.Key.CompareContent(day.Name)); if (constraintDay.Key == null) { continue; } // if the employee asked for this shift skip if (constraintDay.Value.CompareContent(shift.Name)) { continue; } weight += _unwantedShift; } } } return(weight); } catch (Exception e) { CommonLogic.ApeandToFile(e.ToString()); } return(default);
private bool TryOrAssignEmployee(Schedulare schedulare, Day schedulareDay, Shift schedulareShift, bool validate = true) { var randomEmployee = GetRandomEmployee(); if (validate) // validate if the employee can enter the shift { if (!CommonLogic.IsValidToAssign(schedulare, schedulareDay, schedulareShift, randomEmployee)) { return(false); } } // add worker to the schedulare schedulareShift.Workers.Add(randomEmployee); // remove worker from the backlog _workersBackLog.Remove(randomEmployee); return(true); }
private void RunAlgo(ShiftsContainer shiftsContainer, Schedulare schedulare, SchedulareState randResult, KeyValuePair <string, IAlgo> algo) { SchedulareState result = null; if (algo.Key.ContainsContent("rand")) { return; } if (algo.Key.ContainsContent("tabu")) { result = algo.Value.Execute(randResult.Node.Value.DeepClone(), shiftsContainer); } else { result = algo.Value.Execute(schedulare.DeepClone(), shiftsContainer); } PrintDebugData(shiftsContainer, result, algo.Key.ToString()); UpdateSchefulareStatistics(shiftsContainer, result, algo.Key.ToString()); }
private void ResolveAndFillTheSchdulare(Schedulare schedulare, ShiftsContainer shiftsContainer) { var numberOfWokersInShift = shiftsContainer.ShiftParams.NumberOfWokersInShift; while (!_workersBackLog.Count.Equals(0)) { // get available shifts var days = schedulare.Days.DeepClone(); var tempAvailableShifts = days.Select(x => new { x.Name, Shifts = x.Shifts.Where(y => y.Workers.Count < numberOfWokersInShift).ToList() }).ToList(); var availableShifts = tempAvailableShifts.Where(x => !x.Shifts.IsNullOrEmpty()).ToList(); // fetch shift from back log var backLogShiftDayToFill = availableShifts.FirstOrDefault(); var backLogShiftToFill = new { backLogShiftDayToFill.Name, Shift = backLogShiftDayToFill.Shifts.FirstOrDefault() }; // fetch matching shift from schedulare as was fetched from the backlog var schedulareDay = schedulare.Days.FirstOrDefault(x => x.Name.ContainsContent(backLogShiftDayToFill.Name)); var schedulareShift = schedulareDay.Shifts.FirstOrDefault(x => x.Name.CompareContent(backLogShiftToFill.Shift.Name)); AssignRandomEmployee(schedulare, schedulareDay, schedulareShift); } }
public override SchedulareState Execute(Schedulare schedulare, ShiftsContainer shiftsContainer) { this.schedulare = schedulare; this.shiftsContainer = shiftsContainer; greedyEmpList = new List <GreedyEmployee>(); _executeStopwatch.Start(); StartAlgorithm(); var executionTime = _executeStopwatch.Elapsed.TotalSeconds; _executeStopwatch.Reset(); conflicts = new List <GreedyEmployee>(); var schedulareState = GetSchedulareState(schedulare, shiftsContainer, new TreeNode <Schedulare>(schedulare)); schedulareState.ExecuteTime = executionTime; return(schedulareState); }
public override SchedulareState Execute(Schedulare schedulare, ShiftsContainer shiftsContainer) { InitParams(schedulare, shiftsContainer); var schedulareState = GetSchedulareState(schedulare.DeepClone(), shiftsContainer, TreeRoot); UpdateCurrentBestSolution(schedulareState); OpenSet.Add(schedulareState); ExecuteStopwatch.Start(); var shiftsList = GetShiftList(schedulareState.Node.Value); while (!IsGoal()) { var randShift = GetRandomShift(shiftsList); // DEBUG PrintDebugData(shiftsContainer, CurrentBestSolution); ExplorationStopwatch.Reset(); ExplorationStopwatch.Start(); #region Exploration loop while (ExplorationStopwatch.Elapsed.TotalSeconds < EXPLORATION_TIME_SECONDS) { // IsGoal // OR break id exploration ended with no result if (IsGoal() || OpenSet.Count.Equals(0)) { break; } var currState = OpenSet.FindMin(); UpdateCurrentBestSolution(currState); OpenSet.DeleteMin(); CloseSet.Add(currState.Node.Value); for (int workerIndex = 0; workerIndex < randShift.Shift.Workers.Count; workerIndex++) { var currStateInOrderToReplaceEmp = currState.DeepClone(); var currStateNodeInOrderToReplaceEmp = currStateInOrderToReplaceEmp.Node; RemoveEmpFromCurrShift(randShift, workerIndex, currStateInOrderToReplaceEmp); // DEBUG PrintDebugData(shiftsContainer, currStateInOrderToReplaceEmp); #region build new nodes foreach (var emp in shiftsContainer.EmployeeConstraints.Select(x => x.Name)) { var newNodeSchedulare = currStateNodeInOrderToReplaceEmp.Value.DeepClone(); var currShiftToAssin = GetIncompleteShift(newNodeSchedulare, shiftsContainer); // modify schdulare currShiftToAssin.Workers.Remove(currShiftToAssin.Workers.FirstOrDefault(x => x.Name.IsNullOrEmpty())); currShiftToAssin.Workers.Add(new Worker() { Name = emp }); // validate if the new state in tabu list - is yes ignore it if (CloseSet.Contains(newNodeSchedulare)) { if (!DEBUG) { continue; } Console.WriteLine($"####### Tabu list filterd #######"); continue; } // add new node to the tree - currNode var childNode = currStateNodeInOrderToReplaceEmp.AddChild(newNodeSchedulare); // get new state var newNodeState = GetSchedulareState(newNodeSchedulare, shiftsContainer, childNode); // add new state to openSet OpenSet.Add(newNodeState); // DEBUG PrintDebugData(shiftsContainer, newNodeState); } #endregion } } ExplorationStopwatch.Stop(); #endregion if (IsGoal()) { break; } } var ret = CurrentBestSolution; CurrentBestSolution = null; IsFinished = false; ExecuteStopwatch.Reset(); return(ret); }
public override SchedulareState Execute(Schedulare schedulare, ShiftsContainer shiftsContainer) { InitParams(schedulare, shiftsContainer); var schedulareState = GetSchedulareState(schedulare.DeepClone(), shiftsContainer, TreeRoot); OpenSet.Add(schedulareState); ExecuteStopwatch.Start(); while (!OpenSet.IsEmpty) { var currState = OpenSet.FindMin(); OpenSet.DeleteMin(); CloseSet.Add(currState); var currNode = currState.Node; UpdateCurrentBestSolution(currState); if (IsGoal() && IsSchedulareFull(currNode.Value, shiftsContainer)) { UpdateCurrentBestSolution(currState); break; } // DEBUG PrintDebugData(shiftsContainer, currState); // if the current node is full schedulare but it is not goal yet // remove the node from open list and look for another solutions if (IsSchedulareFull(currNode.Value, shiftsContainer)) { OpenSet.DeleteMin(); CloseSet.Add(currState); continue; } // create and add child nodes #region build new nodes foreach (var emp in shiftsContainer.EmployeeConstraints.Select(x => x.Name)) { var newNodeSchedulare = currNode.Value.DeepClone(); var currShiftToAssin = GetIncompleteShift(newNodeSchedulare, shiftsContainer); // modify schdulare currShiftToAssin.Workers.Add(new Worker() { Name = emp }); // add new node to the tree - currNode var childNode = currNode.AddChild(newNodeSchedulare); // get new state var newNodeState = GetSchedulareState(newNodeSchedulare, shiftsContainer, childNode); // add new state to openSet OpenSet.Add(newNodeState); } #endregion } // DEBUG PrintDebugData(shiftsContainer, CurrentBestSolution); var ret = CurrentBestSolution; CurrentBestSolution = null; IsFinished = false; ExecuteStopwatch.Reset(); return(ret); }
public static bool IsValidToAssign(Schedulare _schedulare, Day _schedulareDay, Shift _schedulareShift, Worker _randomEmployee) { try { // if employee is in the shift if (IsEmployeeInShift(_schedulareShift, _randomEmployee)) { return(false); } // if employee is in prev shift var shiftIndex = _schedulareDay.Shifts.FindIndex(x => x.Name.CompareContent(_schedulareShift.Name)); Shift shiftToValidate; if (shiftIndex > 0) { shiftToValidate = _schedulareDay.Shifts[shiftIndex - 1]; if (IsEmployeeInShift(shiftToValidate, _randomEmployee)) { return(false); } } else if (!_schedulareDay.Name.ContainsContent("sunday")) // shiftIndex == 0 and we need to check the prev day last shift // at current logic we do not support 2 week therefore is its sunday we aprove { var dayIndex = _schedulare.Days.FindIndex(x => x.Name.ContainsContent(_schedulareDay.Name)); Day dayToValidate = _schedulare.Days[dayIndex - 1]; shiftToValidate = dayToValidate.Shifts.LastOrDefault(); if (IsEmployeeInShift(shiftToValidate, _randomEmployee)) { return(false); } } // if employee is in next shift shiftIndex = _schedulareDay.Shifts.FindIndex(x => x.Name.CompareContent(_schedulareShift.Name)); if (shiftIndex < _schedulareDay.Shifts.Count() - 1) { shiftToValidate = _schedulareDay.Shifts[shiftIndex + 1]; if (IsEmployeeInShift(shiftToValidate, _randomEmployee)) { return(false); } } else if (!_schedulareDay.Name.ContainsContent("saturday")) // shiftIndex == last shift and we need to check the next day first shift // at current logic we do not support 2 week therefore is its saturday we aprove { var dayIndex = _schedulare.Days.FindIndex(x => x.Name.ContainsContent(_schedulareDay.Name)); Day dayToValidate = _schedulare.Days[dayIndex + 1]; shiftToValidate = dayToValidate.Shifts.FirstOrDefault(); if (IsEmployeeInShift(shiftToValidate, _randomEmployee)) { return(false); } } return(true); } catch (Exception e) { ApeandToFile(e.ToString()); } return(default);
public abstract SchedulareState Execute(Schedulare schedulare, ShiftsContainer shiftsContainer);