#region License Information
/* HeuristicLab
* Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeuristicLab.Core;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Common;
using HeuristicLab.Data;
using HeuristicLab.Encodings.PermutationEncoding;
using HeuristicLab.Optimization;
using HeuristicLab.Parameters;
using HeuristicLab.Encodings.SchedulingEncoding.JobSequenceMatrix;
using HeuristicLab.Encodings.SchedulingEncoding;
using HeuristicLab.Problems.Scheduling.Interfaces;
namespace HeuristicLab.Problems.Scheduling.Decoders {
[Item("Job Sequence Matrix Decoder", "Applies the GifflerThompson algorithm to create an active schedule from a JobSequence Matrix.")]
[StorableClass]
public class JSMDecoder : SchedulingDecoder, IStochasticOperator, IJSSPOperator {
[StorableConstructor]
protected JSMDecoder(bool deserializing) : base(deserializing) { }
protected JSMDecoder(JSMDecoder original, Cloner cloner)
: base(original, cloner) {
this.resultingSchedule = cloner.Clone(original.resultingSchedule);
this.jobs = cloner.Clone(original.jobs);
this.decodingErrorPolicy = original.decodingErrorPolicy;
this.forcingStrategy = original.forcingStrategy;
}
public override IDeepCloneable Clone(Cloner cloner) {
return new JSMDecoder(this, cloner);
}
public ILookupParameter RandomParameter {
get { return (LookupParameter)Parameters["Random"]; }
}
public ILookupParameter> JobDataParameter {
get { return (LookupParameter>)Parameters["JobData"]; }
}
#region Private Members
[Storable]
private Schedule resultingSchedule;
[Storable]
private ItemList jobs;
[Storable]
private JSMDecodingErrorPolicyTypes decodingErrorPolicy = JSMDecodingErrorPolicyTypes.GuidedPolicy;
[Storable]
private JSMForcingStrategyTypes forcingStrategy = JSMForcingStrategyTypes.ShiftForcing;
#endregion
public JSMDecoder()
: base() {
Parameters.Add(new LookupParameter("Random", "The pseudo random number generator which should be used for stochastic manipulation operators."));
Parameters.Add(new LookupParameter>("JobData", "Job data taken from the Schedulingproblem - Instance."));
}
private Task SelectTaskFromConflictSet(int conflictedResourceNr, int progressOnConflictedResource, ItemList conflictSet, ItemList jsm) {
if (conflictSet.Count == 1)
return conflictSet[0];
//get solutionCandidate from jobSequencingMatrix
int solutionCandidateJobNr = jsm[conflictedResourceNr][progressOnConflictedResource];
//scan conflictSet for given solutionCandidate, and return if found
foreach (Task t in conflictSet) {
if (t.JobNr.Value == solutionCandidateJobNr)
return t;
}
//if solutionCandidate wasn't found in conflictSet apply DecodingErrorPolicy and ForcingPolicy
Task result = ApplyDecodingErrorPolicy(conflictSet, jsm[conflictedResourceNr], progressOnConflictedResource);
int newResolutionIndex = 0;
while (newResolutionIndex < jsm[conflictedResourceNr].Length && jsm[conflictedResourceNr][newResolutionIndex] != result.JobNr.Value)
newResolutionIndex++;
ApplyForcingStrategy(jsm, conflictedResourceNr, newResolutionIndex, progressOnConflictedResource, result.JobNr.Value);
return result;
}
private Task ApplyDecodingErrorPolicy(ItemList conflictSet, Permutation resource, int progress) {
if (decodingErrorPolicy == JSMDecodingErrorPolicyTypes.RandomPolicy) {
//Random
return conflictSet[RandomParameter.ActualValue.Next(conflictSet.Count - 1)];
} else {
//Guided
for (int i = progress; i < resource.Length; i++) {
int j = 0;
while (j < conflictSet.Count && conflictSet[j].JobNr.Value != resource[i])
j++;
if (j < conflictSet.Count)
return (conflictSet[j]);
}
return conflictSet[RandomParameter.ActualValue.Next(conflictSet.Count - 1)];
}
}
private void ApplyForcingStrategy(ItemList jsm, int conflictedResource, int newResolutionIndex, int progressOnResource, int newResolution) {
if (forcingStrategy == JSMForcingStrategyTypes.SwapForcing) {
//SwapForcing
jsm[conflictedResource][newResolutionIndex] = jsm[conflictedResource][progressOnResource];
jsm[conflictedResource][progressOnResource] = newResolution;
} else {
//ShiftForcing
List asList = jsm[conflictedResource].ToList();
if (newResolutionIndex > progressOnResource) {
asList.RemoveAt(newResolutionIndex);
asList.Insert(progressOnResource, newResolution);
} else {
asList.Insert(progressOnResource, newResolution);
asList.RemoveAt(newResolutionIndex);
}
jsm[conflictedResource] = new Permutation (PermutationTypes.Absolute, asList.ToArray());
}
}
public Schedule CreateScheduleFromEncoding(JSMEncoding solution, ItemList jobData) {
ItemList jobSequenceMatrix = solution.JobSequenceMatrix;
jobs = (ItemList)jobData.Clone();
resultingSchedule = new Schedule(new IntValue(jobs[0].Tasks.Count));
//Reset scheduled tasks in result
foreach (Job j in jobs) {
foreach (Task t in j.Tasks) {
t.IsScheduled.Value = false;
}
}
//GT-Algorithm
//STEP 0 - Compute a list of "earliest operations"
ItemList earliestTasksList = GTAlgorithmUtils.GetEarliestNotScheduledTasks(jobs);
while (earliestTasksList.Count > 0) {
//STEP 1 - Get earliest not scheduled operation with minimal earliest completing time
Task minimal = GTAlgorithmUtils.GetTaskWithMinimalEC(earliestTasksList, resultingSchedule);
int conflictedResourceNr = minimal.ResourceNr.Value;
Resource conflictedResource = resultingSchedule.Resources[conflictedResourceNr];
//STEP 2 - Compute a conflict set of all operations that can be scheduled on the conflicted resource
ItemList conflictSet = GTAlgorithmUtils.GetConflictSetForTask(minimal, earliestTasksList, jobs, resultingSchedule);
//STEP 3 - Select a task from the conflict set
int progressOnResource = conflictedResource.Tasks.Count;
Task selectedTask = SelectTaskFromConflictSet(conflictedResourceNr, progressOnResource, conflictSet, jobSequenceMatrix);
//STEP 4 - Add the selected task to the current schedule
selectedTask.IsScheduled.Value = true;
double startTime = GTAlgorithmUtils.ComputeEarliestStartTime(selectedTask, resultingSchedule);
resultingSchedule.ScheduleTask(selectedTask.ResourceNr.Value, startTime, selectedTask.Duration.Value, selectedTask.JobNr.Value);
//STEP 5 - Back to STEP 1
earliestTasksList = GTAlgorithmUtils.GetEarliestNotScheduledTasks(jobs);
}
return resultingSchedule;
}
public override Schedule CreateScheduleFromEncoding(JSMEncoding solution) {
return CreateScheduleFromEncoding(solution, JobDataParameter.ActualValue);
}
public override IOperation Apply() {
return base.Apply();
}
}
}