public static List<LaneSchedulerAction> GetActions(LaneSchedulerState state, List<LaneSchedulerReservation> reservations) { List<LaneSchedulerAction> actions = new List<LaneSchedulerAction>(); foreach (LaneSchedulerReservation reservation in reservations) { foreach (LaneSchedulerAction action in Expand(state, reservation)) { actions.Add(action); // add at the end of list, so they are in order } } return actions; }
public static List<LaneSchedulerReservation> GetAlternativeReservations(LaneSchedulerState state, LaneSchedulerReservation reservation) { List<LaneSchedulerReservation> reservations = new List<LaneSchedulerReservation>(); if (reservation.StartTimeSlot - 1 > 0) { LaneSchedulerReservation altReservation1 = new LaneSchedulerReservation(reservation.Id, reservation.NumberOfLanes, reservation.NumberOfTimeSlots, reservation.StartTimeSlot - 1); List<LaneSchedulerAction> actions = LaneScheduler.Expand(state, altReservation1); if (actions.Count > 0) { reservations.Add(altReservation1); } int numTimeSlots = reservation.NumberOfTimeSlots - 1; while (numTimeSlots > 0) { LaneSchedulerReservation altReservation2 = new LaneSchedulerReservation(reservation.Id, reservation.NumberOfLanes, numTimeSlots, reservation.StartTimeSlot - 1); List<LaneSchedulerAction> actions2 = LaneScheduler.Expand(state, altReservation2); if (actions2.Count > 0) { reservations.Add(altReservation2); } numTimeSlots--; } } if (reservation.StartTimeSlot + 1 < state.numberOfTimeSlots) { LaneSchedulerReservation altReservation1 = new LaneSchedulerReservation(reservation.Id, reservation.NumberOfLanes, reservation.NumberOfTimeSlots, reservation.StartTimeSlot + 1); List<LaneSchedulerAction> actions = LaneScheduler.Expand(state, altReservation1); if (actions.Count > 0) { reservations.Add(altReservation1); } int numTimeSlots = reservation.NumberOfTimeSlots - 1; while (numTimeSlots > 0) { LaneSchedulerReservation altReservation2 = new LaneSchedulerReservation(reservation.Id, reservation.NumberOfLanes, numTimeSlots, reservation.StartTimeSlot + 1); List<LaneSchedulerAction> actions2 = LaneScheduler.Expand(state, altReservation2); if (actions2.Count > 0) { reservations.Add(altReservation2); } numTimeSlots--; } } return reservations; }
public static List<LaneSchedulerAction> Expand(LaneSchedulerState state, LaneSchedulerReservation reservation) { List<LaneSchedulerAction> actions = new List<LaneSchedulerAction>(); if (state.IsPossible(reservation)) { for (int lane = 0; lane < state.numberOfLanes; lane++) { AppWeightPair appWeightPair = state.IsApplicable(lane, reservation.NumberOfLanes, reservation.NumberOfTimeSlots, reservation.StartTimeSlot); if (appWeightPair.applicable) { actions.Add(new LaneSchedulerAction(lane, reservation, appWeightPair.weight)); } } } return actions; }
public LaneSchedulerState Convert(IList<Reservation> reservations, out List<LaneSchedulerReservation> schedulerReservations) { schedulerReservations = (from y in reservations select new LaneSchedulerReservation() { Id = y.Id, NumberOfLanes = (int)Math.Ceiling(y.NumberOfPlayers / 6.0m), NumberOfTimeSlots = y.TimeSlots.Count, StartTimeSlot = y.TimeSlots[0].Id -1 }).ToList(); var state = new LaneSchedulerState( this.laneRepos.GetAll().Count(), this.timeSlotRepos.GetAll().Count(), schedulerReservations); // iterate all of the reservations in order to put them into the internal state array of the sched. int[,] internalState = state.State; int laneId = 0; int slotId = 0; foreach (var resv in reservations) { foreach (var lane in resv.Lanes) { foreach (var slot in resv.TimeSlots) { laneId = lane.Id-1; slotId = slot.Id-1; if (internalState[slotId, laneId] != 0) { throw new InvalidOperationException(String.Format("The scheduler state at position {0}, {1} is already taken. This means that one or more reservations have been allocated to the same lane and slot. Not so good")); } internalState[slotId, laneId] = resv.Id; } } } state.State = internalState; return state; }
public static bool Test_n_reservations(int numberOfLanes, int numberOfTimeSlots, int numberOfVisitors, int runLimit) { Debug.WriteLine("Testing scheduling of " + numberOfVisitors + " visitors in " + numberOfLanes + " lanes and " + numberOfTimeSlots + " timeslots"); LaneWearData.Populate(numberOfLanes); List<LaneSchedulerReservation> reservations = new List<LaneSchedulerReservation>(); // Reservation(int id, int numLanes, int numTimeSlots, int startTimeSlot) bool run = true; //State emptyState = new State(numberOfLanes, numberOfTimeSlots, reservations); LaneSchedulerState state = new LaneSchedulerState(numberOfLanes, numberOfTimeSlots, reservations); LaneSchedulerState newState = null; int i = 0; int visitors = 0; int runs = 0; long timeSpent = 0; Random random = new Random(); while (run) { int numVisitors = 4; int numTimeSlots = random.Next(1, 3); int startTimeSlot = 6; // random.Next(0, numberOfTimeSlots); if (random.Next(0, 100) < 10) { // 10 percent will be parties and outings numVisitors = random.Next(5, 41); } else { numVisitors = random.Next(3, 7); } if (random.Next(0, 100) < 15) { startTimeSlot = random.Next(0, numberOfTimeSlots); } else { startTimeSlot = random.Next(2, numberOfTimeSlots - 2); } int numLanes = 0; if (numVisitors % 6 == 0) { numLanes = numVisitors / 6; } else { numLanes = (numVisitors / 6) + 1; } long time1 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; int id = i + 1; LaneSchedulerReservation reservation = new LaneSchedulerReservation(id, numLanes, numTimeSlots, startTimeSlot); Debug.WriteLine("Making reservation id: " + id + " of " + numLanes + " lanes for " + numTimeSlots + " hours, at timeslot " + startTimeSlot); List<LaneSchedulerReservation> newReservations = new List<LaneSchedulerReservation>(reservations); newReservations.Add(reservation); //emptyState = new State(numberOfLanes, numberOfTimeSlots, newReservations); LaneSchedulerStateReservationsPair result = LaneScheduler.Search(state, reservations, reservation); newState = result.state; long time2 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; timeSpent = time2 - time1; Debug.WriteLine(" Scheduling took: " + timeSpent + " miliseconds"); if (newState != null) { Debug.WriteLine(" It SUCCEEDED!!!!!!!!"); Debug.WriteLine(newState.ToString()); reservations = newReservations; state = newState; visitors = visitors + numVisitors; Debug.WriteLine("Have now scheduled for: " + visitors + " visitors"); i++; } else { Debug.WriteLine(" It failed. Alternative reservations are:"); for (int j = 0; j < result.reservations.Count; j++) { Debug.WriteLine(" Reservation for " + result.reservations[j].NumberOfLanes + " lanes at slot: " + result.reservations[j].StartTimeSlot + " for " + result.reservations[j].NumberOfTimeSlots + " hours"); } } if (visitors > numberOfVisitors) { run = false; } if (runs > runLimit) { run = false; } runs++; } Debug.WriteLine("The last scheduling took: " + timeSpent + " miliseconds"); if (state != null) { Debug.WriteLine(state.ToString()); } return true; }
public static LaneSchedulerState RecursiveSearch(LaneSchedulerState state, List<LaneSchedulerReservation> reservations, int depth, long timelimit, long time) { if (time > timelimit) { //Debug.WriteLine("TIME LIMIT EXCEEDED-1! Time was: " + time); return null; } long time1 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; //Debug.WriteLine("Reached depth: " + depth); if (reservations.Count == 0) { return state; } reservations = (from y in reservations select y).OrderBy(y => state.GetReservationWeight(y)).ToList<LaneSchedulerReservation>(); foreach (LaneSchedulerReservation reservation in reservations) { // Get applicable actions List<LaneSchedulerAction> actions = Expand(state, reservation); actions = (from y in actions select y).OrderBy(y => y.weight).ToList<LaneSchedulerAction>(); // Loop for actions in a depth-first manner, backtracking if no solution is found. for (int num = 0; num < actions.Count; num++) { LaneSchedulerAction action = actions[num]; state.Apply(action); //if (!Scheduler.closedStateList.ContainsKey(state.ReservationRepr(action.reservation))) //{ List<LaneSchedulerReservation> remainingReservations = new List<LaneSchedulerReservation>(reservations); remainingReservations.Remove(action.reservation); int newDepth = depth + 1; long time2 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; long runTime = time2 - time1; time = time + runTime; LaneSchedulerState solution = RecursiveSearch(state, remainingReservations, newDepth, timelimit, time); if (solution != null) { //Debug.WriteLine("Placed reservation: " + action.reservation.id); return solution; } else { //string stateRepr = state.ReservationRepr(action.reservation); //if (!Scheduler.closedStateList.ContainsKey(stateRepr)) //{ // Scheduler.closedStateList.Add(stateRepr, 1); //} state.Unapply(action); if (time > timelimit) { //Debug.WriteLine("TIME LIMIT EXCEEDED-2! Time was: " + time); return null; } //Debug.WriteLine(state.toString()); } //}else{ //Debug.WriteLine(" Hit an explored state!"); //Debug.WriteLine(state.toString()); //Debug.WriteLine(" " + state.ReservationRepr(action.reservation)); //state.Unapply(action); //return null; //} } //Debug.WriteLine(" Backtracking"); //Debug.WriteLine(state.toString()); } return null; }
public static LaneSchedulerStateReservationsPair Search(LaneSchedulerState state, List<LaneSchedulerReservation> reservations, LaneSchedulerReservation newReservation) { LaneScheduler.closedStateList = new Dictionary<string, int>(); Debug.WriteLine("Adding new Reservation"); if (!state.IsPossible(newReservation)) { Debug.WriteLine(" It failed the first check"); // get other reservations return new LaneSchedulerStateReservationsPair(null, LaneScheduler.GetAlternativeReservations(state, newReservation)); } // if it can be applied easily List<LaneSchedulerAction> actions = Expand(state, newReservation); actions = (from y in actions select y).OrderBy(y => y.weight).ToList<LaneSchedulerAction>(); if (actions.Count > 0) { state.Apply(actions[0]); Debug.WriteLine(" The reservation was straight forward"); return new LaneSchedulerStateReservationsPair(state, new List<LaneSchedulerReservation>()); } // else, search // cut the relevant piece out of the state, so we end up with three pieces. // Solve the middle piece, and add it to the top and bottom piece. //List<State> statePieces = state.cutInPieces(newReservation); List<LaneSchedulerReservation> newReservations = new List<LaneSchedulerReservation>(reservations); newReservations.Add(newReservation); long time1 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; LaneSchedulerState emptyState = new LaneSchedulerState(state.numberOfLanes, state.numberOfTimeSlots, newReservations); LaneSchedulerState newState = LaneScheduler.RecursiveSearch(emptyState, newReservations, 0, 100000, 0); long time2 = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; long runTime = time2 - time1; Debug.WriteLine(" Search took: " + runTime + " ms"); if (newState != null) { Debug.WriteLine(" Returning state"); return new LaneSchedulerStateReservationsPair(newState, new List<LaneSchedulerReservation>()); } else { // get other reservations Debug.WriteLine(" Returning other reservations"); return new LaneSchedulerStateReservationsPair(null, LaneScheduler.GetAlternativeReservations(state, newReservation)); } }
public List<LaneSchedulerState> CutInPieces(LaneSchedulerReservation reservation) { List<LaneSchedulerState> stateList = new List<LaneSchedulerState>(); // detect cutting lines // find cutting line for upper part int upperCut = -1; for (int i = reservation.StartTimeSlot + reservation.NumberOfTimeSlots; i < this.numberOfTimeSlots; i++) { bool foundAny = false; for (int j = 0; j < this.numberOfLanes; j++) { if (this.state[i, j] == this.state[i + 1, j] || this.state[i, j] == this.state[i - 1, j]) { foundAny = true; } if (!foundAny) { upperCut = i; break; } } } // find cutting line for lower part int lowerCut = -1; for (int i = reservation.StartTimeSlot - 1; i >= 0; i--) { bool foundAny = false; for (int j = 0; j < this.numberOfLanes; j++) { if (this.state[i, j] == this.state[i + 1, j] || this.state[i, j] == this.state[i - 1, j]) { foundAny = true; } if (!foundAny) { lowerCut = i; break; } } } // do the cutting LaneSchedulerState stateUpper = new LaneSchedulerState(this.numberOfLanes, this.numberOfTimeSlots, new List<LaneSchedulerReservation>()); stateUpper.weight = this.weight; stateUpper.weight = this.weight; stateUpper.state = new int[numberOfTimeSlots, numberOfLanes]; LaneSchedulerState stateMiddle = new LaneSchedulerState(this.numberOfLanes, this.numberOfTimeSlots, new List<LaneSchedulerReservation>()); stateMiddle.weight = this.weight; stateMiddle.weight = this.weight; stateMiddle.state = new int[numberOfTimeSlots, numberOfLanes]; LaneSchedulerState stateLower = new LaneSchedulerState(this.numberOfLanes, this.numberOfTimeSlots, new List<LaneSchedulerReservation>()); stateLower.weight = this.weight; stateLower.weight = this.weight; stateLower.state = new int[numberOfTimeSlots, numberOfLanes]; // Populate them for (int i = 0; i < this.numberOfTimeSlots; i++) { for (int j = 0; j < this.numberOfLanes; j++) { if (i <= lowerCut) { stateLower.state[i, j] = this.state[i, j]; } else if (j >= upperCut) { stateMiddle.state[i, j] = this.state[i, j]; } else { stateUpper.state[i, j] = this.state[i, j]; } } } stateList.Add(stateUpper); stateList.Add(stateMiddle); stateList.Add(stateLower); return stateList; }
public List<Reservation> Convert(LaneSchedulerState state, out Reservation newReservation) { int [,] internalState = state.State; int current = 0; newReservation = new Reservation(); int laneCount = this.laneRepos.GetAll().Count(); int timeSlotCount = this.timeSlotRepos.GetAll().Count(); List<ReservationLaneTimeSlotPair> pairs = new List<ReservationLaneTimeSlotPair>(); for (int i = 0; i < timeSlotCount; i++) { for (int j = 0; j < laneCount; j++) { current = internalState[i, j]; if (current == 0) { continue; } var pair = new ReservationLaneTimeSlotPair() { LaneId = j+1, TimeSlotId = i+1, ReservationId = current }; pairs.Add(pair); } } // load all reservations besides -1 by first gettting the distinct list of // ids, then loading these from db and converting to a dictionary // then finally clearing all lane and timeslots from these var distinctReservations = (from y in pairs where y.ReservationId != -1 select y.ReservationId).Distinct<int>().ToList(); var distinctTimeSlots = (from y in pairs select y.TimeSlotId).Distinct<int>().ToList(); var distinctLanes = (from y in pairs select y.LaneId).Distinct<int>().ToList(); var reservations = (from y in reservationRepos.GetAll() where distinctReservations.Contains(y.Id) select y).ToDictionary(t => t.Id, t => t); var timeslots = (from y in timeSlotRepos.GetAll() where distinctTimeSlots.Contains(y.Id) select y).ToDictionary(t => t.Id, t => t); var lanes = (from y in laneRepos.GetAll() where distinctLanes.Contains(y.Id) select y).ToDictionary(t => t.Id, t => t); foreach (var r in reservations) { r.Value.Lanes.Clear(); r.Value.TimeSlots.Clear(); } // now we can reschedule all of the reservations, and add the lanes and timeslots // to the new reservation as well foreach (var pair in pairs) { if (pair.ReservationId == -1) { newReservation.AddLane(lanes[pair.LaneId]); newReservation.AddTimeSlot(timeslots[pair.TimeSlotId]); continue; } reservations[pair.ReservationId].AddLane(lanes[pair.LaneId]); reservations[pair.ReservationId].AddTimeSlot(timeslots[pair.TimeSlotId]); } var toReturn = new List<Reservation>(); foreach(var r in reservations) { toReturn.Add(r.Value); } distinctLanes = null; distinctReservations = null; distinctTimeSlots = null; return toReturn; }
public LaneSchedulerStateReservationsPair(LaneSchedulerState state, List<LaneSchedulerReservation> reservations) { this.state = state; this.reservations = reservations; }