public void ShouldBuildPlanForSimpleCase1() { //Arrange var firstJob = new Job(1, 10, null, .1, 2); var secondJob = new Job(2, 10, new List<int> { 1 }, .1, 2); var thirdJob = new Job(3, 20, new List<int> { 1, 2 }, .1, 2); var jobs = new List<Job> { firstJob, secondJob, thirdJob }; var resource1 = new Resource(1, 20); var resources = new List<Resource> { resource1 }; var dependencies = new List<double[]> { new double[] { 7 }, new double[] { 14 }, new double[] { 10 } }; var planBuilder = new JobPlanBuilder(); //Act var plan = planBuilder.GetBasePlan(resources, jobs, dependencies); //Assert AreEqual(plan.Count(), 3); AreEqual(plan[0].ExecutingJobs.Count, 1); AreEqual(plan[0].ExecutingJobs[0].JobReference.Number, 1); True(plan[0].ExecutingJobs[0].Intencity.FloatEquals(2)); True(plan[0].TimeDelta.FloatEquals(5)); AreEqual(plan[1].ExecutingJobs.Count, 1); AreEqual(plan[1].ExecutingJobs[0].JobReference.Number, 2); True(plan[1].ExecutingJobs[0].Intencity.FloatEquals(1.42857142857)); True(plan[1].TimeDelta.FloatEquals(7)); AreEqual(plan[2].ExecutingJobs.Count, 1); AreEqual(plan[2].ExecutingJobs[0].JobReference.Number, 3); AreEqual(plan[2].ExecutingJobs[0].Intencity, 2); True(plan[2].TimeDelta.FloatEquals(10)); }
public void ShouldCreateCorrectDataContainer() { //Arrange var firstJob = new Job(1, 100, null, 1, 10); var secondJob = new Job(2, 100, new List<int> {1}, 1, 10); var thirdJob = new Job(3, 200, new List<int>{1, 2}, 1, 20); var jobs = new List<Job> { firstJob, secondJob, thirdJob }; var resource1 = new Resource(1, 10); var resource2 = new Resource(2, 30); var resources = new List<Resource> { resource1, resource2 }; var dependencies = new List<double[]> { new[] {0.7, 1.2} , new[] {1.4, 0.8}, new[] {1.0,2.0} }; //Act var container = new SchedulingDataContainer(resources, jobs, dependencies); //Assert AreEqual(container.Jobs, jobs); AreEqual(container.Resources, resources); AreEqual(container.Jobs[0].Number, 1); AreEqual(container.Jobs[0].FullWorkVolume, 100); AreEqual(container.Jobs[0].MinimumIntensity, 1); AreEqual(container.Jobs[0].MaximumIntensity, 10); AreEqual(container.Jobs[0].ResourceDependencies.Count, 2); AreEqual(container.Jobs[0].PrecedingJobs.Count, 0); AreEqual(container.Jobs[0].NumberOfDependants, 2); AreEqual(container.Jobs[0].ResourceDependencies[0].Job, firstJob); AreEqual(container.Jobs[0].ResourceDependencies[0].Resource, resource1); AreEqual(container.Jobs[0].ResourceDependencies[0].Value, 0.7); AreEqual(container.Jobs[0].ResourceDependencies[1].Job, firstJob); AreEqual(container.Jobs[0].ResourceDependencies[1].Resource, resource2); AreEqual(container.Jobs[0].ResourceDependencies[1].Value, 1.2); AreEqual(container.Jobs[1].Number, 2); AreEqual(container.Jobs[1].PrecedingJobs.Count, 1); AreEqual(container.Jobs[1].PrecedingJobs[0], firstJob); AreEqual(container.Jobs[1].NumberOfDependants, 1); AreEqual(container.Jobs[1].ResourceDependencies.Count, 2); AreEqual(container.Jobs[1].ResourceDependencies[0].Job, secondJob); AreEqual(container.Jobs[1].ResourceDependencies[0].Resource, resource1); AreEqual(container.Jobs[1].ResourceDependencies[0].Value, 1.4); AreEqual(container.Jobs[1].ResourceDependencies[1].Job, secondJob); AreEqual(container.Jobs[1].ResourceDependencies[1].Resource, resource2); AreEqual(container.Jobs[1].ResourceDependencies[1].Value, 0.8); AreEqual(container.Jobs[2].Number, 3); AreEqual(container.Jobs[2].PrecedingJobs.Count, 2); AreEqual(container.Jobs[2].PrecedingJobs[0], firstJob); AreEqual(container.Jobs[2].PrecedingJobs[1], secondJob); AreEqual(container.Jobs[2].ResourceDependencies.Count, 2); AreEqual(container.Jobs[2].ResourceDependencies[0].Job, thirdJob); AreEqual(container.Jobs[2].ResourceDependencies[0].Resource, resource1); AreEqual(container.Jobs[2].ResourceDependencies[0].Value, 1.0); AreEqual(container.Jobs[2].ResourceDependencies[1].Job, thirdJob); AreEqual(container.Jobs[2].ResourceDependencies[1].Resource, resource2); AreEqual(container.Jobs[2].ResourceDependencies[1].Value, 2.0); }
private PlanModel CreateFakePlanModel() { var firstJob = new Job(1, 10, null, .1, 2); var secondJob = new Job(2, 10, new List<int> {1}, .1, 2); var thirdJob = new Job(3, 20, new List<int> {1, 2}, .1, 2); var fourthJob = new Job(4, 20, null, .1, 2); var jobs = new List<Job> {firstJob, secondJob, thirdJob, fourthJob}; var resource1 = new Resource(1, 20); var resources = new List<Resource> {resource1}; var dependencies = new List<double[]> {new double[] {7}, new double[] {14}, new double[] {10}, new double[] {6}}; var planBuilder = new JobPlanBuilder(); var plan = planBuilder.GetBasePlan(resources, jobs, dependencies); var planModel = new PlanModel(plan); return planModel; }
public List<PlanStep> GetBasePlan(IEnumerable<Resource> resources, IEnumerable<Job> jobs, IEnumerable<double[]> dependencyValues) { //Initialization var dataContainer = new SchedulingDataContainer(resources, jobs, dependencyValues); var plan = new List<PlanStep>(); var unfinishedJobs = new LinkedList<Job>(dataContainer.Jobs); var resArr = resources.ToArray(); var resourcesForStep = new Resource[resArr.Length]; int stepNumber = 1; //Repeat while we have unfinished jobs while (unfinishedJobs.Count> 0) { //Set up resources per step for (int r = 0; r < resArr.Length; r++) resourcesForStep[r] = resArr[r].DeepCopy(); //Select jobs we can plan var jobsPossibleToExecute = unfinishedJobs.Where(j => j.CanStart()).ToList(); //Put to heap with greed comparer var jobHeap = new Heap<Job>(jobsPossibleToExecute, jobsPossibleToExecute.Count(), new JobGreedyComparer()); var jobsForStep = new List<RunningJob>(); do { //Take first var jobToExecute = jobHeap.PopRoot(); //Check we can plan it //and compute intensity var maxIntensity = CalcMaxPossibleIntensity(jobToExecute, resourcesForStep); if (maxIntensity > 0) { //Start job jobToExecute.State = JobState.Started; //calc spended resources, remaining resources and time foreach (var resource in resourcesForStep) { var jobResourceDependency = jobToExecute.ResourceDependencies.FirstOrDefault(d => d.Resource.Number == resource.Number); if (jobResourceDependency != null) resource.Value -= jobResourceDependency.Value*maxIntensity; } var time = jobToExecute.RemainingVolume/maxIntensity; jobsForStep.Add(new RunningJob(jobToExecute, maxIntensity, time, plan.LastOrDefault()!=null?plan.LastOrDefault().TimeEnd:0)); } //Repeat while we have some jobs //TODO: Optimize, maybe we don't need to check all jobs } while (jobHeap.Count>0); var stepTime = jobsForStep.Min(j => j.RunTime); var startTime = (plan.Count > 0) ? plan.Last().TimeEnd : 0; //Create PlanStep at this moment var step = new PlanStep(jobsForStep, startTime, stepTime + startTime, stepNumber++); //Compute all jobs to finish foreach (var runningJob in jobsForStep) { if (runningJob.RunTime.FloatEquals(stepTime)) { runningJob.JobReference.State = JobState.Finished; runningJob.JobReference.RemainingVolume = 0; unfinishedJobs.Remove(runningJob.JobReference); } else { var completed = runningJob.Intencity*stepTime; runningJob.JobReference.RemainingVolume -= completed; runningJob.RunTime = step.TimeDelta; } } //Memorize job progress plan.Add(step); } return plan; }
public void ShouldCalculateMaxIntensity1() { //Arrange var firstJob = new Job(1, 10, null, .1, 2); var resource1 = new Resource(1, 20); var dependency = new JobResourceDependency(firstJob, resource1, 7); firstJob.ResourceDependencies.Add(dependency); var planBuilder = new JobPlanBuilder(); //Act var maxIntensity = planBuilder.CalcMaxPossibleIntensity(firstJob, new[] {resource1}); //Assert True(maxIntensity.FloatEquals(2)); }