/// <summary> /// ONLY works for MeanBasedCmax /// </summary> private static bool MoveAndInsertIsImprovement(Schedule ScheduleBeforeMove, Job MoveJob, double ESSv_withoutMachinePred, double Tailtimev_withoutMachinePred, Machine NewMachine, int NewPosIndex, double Currentfitness) { // note Cmax >= Sx + Px + Tx if (Settings.MLS_HF != "DetCmax") { throw new Exception("MoveAndInsertIsImprovement in NeighborhoodFunctions.cs ONLY works for DetCmax"); } double Sv, Tv; if (NewPosIndex == 0) { Sv = ESSv_withoutMachinePred; } else { Job Mpred = NewMachine.AssignedJobs[NewPosIndex - 1]; Sv = Math.Max(ESSv_withoutMachinePred, ScheduleBeforeMove.GetEarliestStart(Mpred) + Mpred.MeanProcessingTime); } if (NewPosIndex == NewMachine.AssignedJobs.Count - 1) { Tv = Tailtimev_withoutMachinePred; } else { Job Msucc = NewMachine.AssignedJobs[NewPosIndex]; // V has not been inserted yet, so this job will be its successor Tv = Math.Min(Tailtimev_withoutMachinePred, ScheduleBeforeMove.CalcTailTime(Msucc) + Msucc.MeanProcessingTime); } if (-(Sv + MoveJob.MeanProcessingTime + Tv) <= Currentfitness + 0.0000001) { //Console.WriteLine("Rejected by bound.. no improvement (no swapping needed)"); return(false); } else { // Do it the hard way. Machine OldMachine = ScheduleBeforeMove.AssignedMachine(MoveJob); int OldPosition = ScheduleBeforeMove.GetIndexOnMachine(MoveJob); ScheduleBeforeMove.DeleteJobFromMachine(MoveJob); ScheduleBeforeMove.AssignJatIndex(MoveJob, NewMachine, NewPosIndex); double NewFitness = FitnessFunctions.MeanBasedCmax(ScheduleBeforeMove); if (NewFitness > Currentfitness) { //improvement return(true); } else { //no improvement //undo swap //reset start times. ScheduleBeforeMove.DeleteJobFromMachine(MoveJob); ScheduleBeforeMove.AssignJatIndex(MoveJob, OldMachine, OldPosition); ScheduleBeforeMove.EstimateCmax(); return(false); } } }
static private bool SwapJobPair(Job J1, Job J2, Machine M, Schedule Sched) { Console.WriteLine("S W A P S T A R T I N G !"); Console.WriteLine("Schedule BEFORE Swap:"); Sched.Print(); Console.WriteLine("Fitness BEFORE swap: {0}", FitnessFunctions.MeanBasedCmax(Sched)); //The bug is that Arrayindex is not the correct position of the job. //Give each job a dictionary of all its transitive descendants. Check in almost O(1) if swap is feasible. (MUCH BETTER THAN BFS). int OldJ1Index = Sched.GetIndexOnMachine(J1);// Sched.MachineArcPointers[J1.ID].ArrayIndex; if (M.AssignedJobs[OldJ1Index] != J1) { throw new Exception("Indexing wrong. J1 index not pointing to J1"); } int OldJ2Index = Sched.GetIndexOnMachine(J2);// Sched.MachineArcPointers[J2.ID].ArrayIndex; if (M.AssignedJobs[OldJ2Index] != J2) { throw new Exception("Indexing wrong. J2 index not pointing to J2"); } int LeftIndex = OldJ1Index; int RightIndex = OldJ2Index; if (OldJ2Index < OldJ1Index) { LeftIndex = OldJ2Index; RightIndex = OldJ1Index; } // check feasibility of the swap, Assuming an already feasible setup. for (int i = LeftIndex; i <= RightIndex - 1; i++) { for (int j = i + 1; j <= RightIndex; j++) { // Between [J1 and J2] (inlusive) the arcs get reversed. Check all combos. //Do they though? TODO BUG! if (Sched.PrecedenceDAG.PrecPathExists(M.AssignedJobs[i], M.AssignedJobs[j])) { // Console.WriteLine("BUG?"); Console.WriteLine("Swap J{0},J{1} on M{2} denied due to cycle from J{3} to J{4}", J1.ID, J2.ID, M.MachineID, M.AssignedJobs[i].ID, M.AssignedJobs[j].ID); return(false); } // infeasible. } } Console.WriteLine("Swapping J{0}, J{1} on M{2}", J1.ID, J2.ID, M.MachineID); UNSAFE_SwapOnMachine(J1, J2, M, Sched); Console.WriteLine("Schedule AFTER Swap:"); Sched.Print(); Console.WriteLine("Fitness AFTER swap: {0}", FitnessFunctions.MeanBasedCmax(Sched)); return(true); }