private TkTimeSet GetVacancy(long weekNumber, TkTimeSet busy) { var workWeekTs = TkTimeSet.WorkWeek(weekNumber); var vacancy = TkTimeSet.Difference(workWeekTs, busy); return(vacancy); }
private TkTimeSet GetVacancy(DateTime start, DateTime end, TkTimeSet busy, TkWorkWeekConfig config) { var workWeeks = TkTimeSet.WorkWeeks(start, end, config); var vacancy = TkTimeSet.Difference(workWeeks, busy); return(vacancy); }
public TkSolution( TkTimeSet mutualVacancy, TkResourceRequestSolutionGroup group, TkResourceResponse[] responses) { MutualVacancy = mutualVacancy; MutualSchedule = TkScheduler.TryScheduling(group.Tasks, mutualVacancy); Group = group; Responses = responses; }
private TkTimeSet GetBusy(IEnumerable <TkProcess> busyProcesses, DateTime start, DateTime end) { var busyTs = new TkTimeSet(busyProcesses .Where(o => o.StartsAt.HasValue && o.EndsAt.HasValue) .Where(o => o.StartsAt.Value >= start && o.EndsAt.Value <= end) .Select(o => new TkInterval(o.StartsAt.Value, o.EndsAt.Value)) .ToArray()); return(busyTs); }
public TkResourceResponse( TkActor actor, TkTimeSet busy, TkTimeSet vacancy, TkTimeSet schedule) { Actor = actor; Busy = busy; Vacancy = vacancy; Schedule = schedule; }
private TkTimeSet GetBusy(IEnumerable <TkProcess> busyProcesses, long weekNumber) { var busyTs = new TkTimeSet( busyProcesses .Where(o => o.StartsAt.HasValue && o.EndsAt.HasValue) .Where(o => DateTimeExtensions.WeekNumber(o.StartsAt.Value) == weekNumber && DateTimeExtensions.WeekNumber(o.EndsAt.Value) == weekNumber) .Select(o => new TkInterval(o.StartsAt.Value, o.EndsAt.Value)) .ToArray()); return(busyTs); }
public static TkTimeSet TryScheduling(IEnumerable <TkTask> tasks, TkTimeSet vacancy) { var scheduledIntervals = new List <TkInterval>(); var workSet = vacancy.Copy(); foreach (var task in tasks) { var scheduledInterval = workSet.ExtractInterval(TimeSpan.FromTicks(task.PlannedDuration)); if (scheduledInterval.isNull) { return(TkTimeSet.Null()); } task.ScheduledInterval = scheduledInterval; scheduledIntervals.Add(scheduledInterval); } var schedule = new TkTimeSet(scheduledIntervals.ToArray()); return(schedule); }
/// <summary> /// Returns a list of solutions where each solution contains a list of actors and their mutual vacancies /// /// THIS ALGORITHM ONLY RETURNS SOLUTIONS WHERE THE ACTORS CAN BE SCHEDULED AT THE EXACT SAME TIME /// /// The recursive algorithm below simply iterates each row(role) and its responses /// 1. Checks if the response vacancy can hold the TicksRequired, if not skip that response /// 2. Passes the vacancy on to the next row /// /// Each pass runs an intersection on the previous row's vacancy and the current row's vacancy /// Once we've passed through all of the rows, we will have the intersection between all of the row vacancies /// Which means that we'll have a TkTimeSet that holds the mutual vacancies for the resources that can perform the required roles /// /// </summary> /// <returns> A list of solutions </returns> public IEnumerable <TkSolution> GetMutualSchedule(int rowIndex = 0) { var solutions = new List <TkSolution>(); var currentRow = Rows[rowIndex]; // base case, exits when we hit the last index if (rowIndex == Rows.Count - 1) { foreach (var response in currentRow.Responses) { var solution = new TkSolution(response.Vacancy, this, new[] { response }); solutions.Add(solution); } } // recursive case, iterates all of the rows and their responses else { foreach (var nextRowSolution in GetMutualSchedule(rowIndex + 1)) { var vacancyFromNextRow = nextRowSolution.MutualVacancy; var responsesFromNextRow = nextRowSolution.Responses; foreach (var responseFromCurrentRow in currentRow.Responses) { var vacancyFromCurrentRow = responseFromCurrentRow.Vacancy; // The current row and the next row must have mutual vacancies var mutualVacancies = TkTimeSet.Intersect(vacancyFromNextRow, vacancyFromCurrentRow); var mutualVacantIntervals = mutualVacancies.GetOrderedIntervals().ToList(); // Check that there's sufficient overlap in vacancies long vacantTicks = 0; foreach (var task in Tasks) { var vacantSlot = mutualVacantIntervals .FirstOrDefault(o => o.Length().Ticks >= task.Duration.Ticks); if (vacantSlot != null) { vacantTicks += vacantSlot.Length().Ticks; mutualVacantIntervals.Remove(vacantSlot); } } if (vacantTicks <= TotalTicksRequired) { continue; } var responsesToPassOn = new TkResourceResponse[responsesFromNextRow.Length + 1]; // Move the previous responses to index 1 and forward, leaving index 0 empty Array.Copy(responsesFromNextRow, 0, responsesToPassOn, 1, responsesFromNextRow.Length); // Add the response and pass it on to the next row responsesToPassOn[0] = responseFromCurrentRow; var solution = new TkSolution(mutualVacancies, this, responsesToPassOn); solutions.Add(solution); } } } return(solutions); }