using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Management.Instrumentation; using System.Text; using System.Threading.Tasks; using HeuristicLab.BioBoost.ProblemDescription; using HeuristicLab.BioBoost.Representation; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.BioBoost.Operators.Mutation { public class PlantMerger : SingleSuccessorOperator, IManipulator, IStochasticOperator { #region Parameters public LookupParameter ProblemDataParameter { get { return (LookupParameter) Parameters["ProblemData"]; } } public LookupParameter DistanceMatrixParameter { get { return (LookupParameter) Parameters["DistanceMatrix"]; } } public ValueParameter DistanceMatrixInProblemDataParameter { get { return (ValueParameter) Parameters["DistanceMatrixInProblemData"]; } } public ValueLookupParameter RegionBoundsParameter { get { return (ValueLookupParameter) Parameters["RegionBounds"]; } } public ILookupParameter RandomParameter { get { return (ILookupParameter) Parameters["Random"]; } } #endregion #region Parameter Values public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } } public IntMatrix RegionBounds { get { return RegionBoundsParameter.ActualValue; } } public IRandom Random { get { return RandomParameter.ActualValue; } } public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } } public DistanceMatrix DistanceMatrix { get { if (DistanceMatrixInProblemData) { return ((IValueParameter) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value; } else { return DistanceMatrixParameter.ActualValue; } } } #endregion #region Construction & Cloning [StorableConstructor] public PlantMerger(bool isDeserializing) {} public PlantMerger(PlantMerger orig, Cloner cloner) : base(orig, cloner) {} public PlantMerger() { Parameters.Add(new LookupParameter("ProblemData", "The data store of the detailed problem description.")); Parameters.Add(new LookupParameter("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this Parameters.Add(new ValueParameter("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true))); Parameters.Add(new ValueLookupParameter("RegionBounds", "The limits of valid region ids.")); Parameters.Add(new LookupParameter("Random", "The random number generator.")); } public override IDeepCloneable Clone(Cloner cloner) { return new PlantMerger(this, cloner); } #endregion public override IOperation Apply() { var scope = ExecutionContext.Scope; var dm = DistanceMatrix; var feedstock = ProblemData.TransportTargets.CheckedItems.ElementAt( Random.Next(ProblemData.TransportTargets.CheckedItems.Count())).Value.Value; string product = null; var productLinks = ProblemData.ProductLinks; for (int i = 0; i < productLinks.Rows; i++) { if (productLinks[i, 0] == feedstock) product = productLinks[i, 1]; } var supplyTransports = scope.Variables[LayerDescriptor.TransportTargets.NameWithPrefix(feedstock)].Value as IntegerVector; var productTransportName = LayerDescriptor.TransportTargets.NameWithPrefix(product); var productTransports = product == null || !scope.Variables.ContainsKey(productTransportName) ? null : scope.Variables[productTransportName].Value as IntegerVector; if (supplyTransports != null) { var plants = supplyTransports.Select((target, source) => new {target, source}).GroupBy(p => p.target).ToList(); var plant = plants.ElementAt(Random.Next(plants.Count)); var allowedRegions = new HashSet(plants.Select(p => p.Key)); var newTarget = FindNewTarget(plant.Key, Random, dm, allowedRegions); foreach (var supplier in plant) { supplyTransports[supplier.source] = newTarget; } if (productTransports != null) { var temp = productTransports[newTarget]; productTransports[newTarget] = productTransports[plant.Key]; productTransports[plant.Key] = temp; } } return base.Apply(); } private int FindNewTarget(int oldTarget, IRandom random, DistanceMatrix distances, IEnumerable allowedRegions) { var neighborDistances = new double[0].Select((d, idx) => new {index = idx, distance = d}).ToList(); var maxDistance = 0d; foreach (int j in allowedRegions) { var dist = distances[oldTarget, j]; neighborDistances.Add(new {index = j, distance = dist}); maxDistance = Math.Max(dist, maxDistance); } neighborDistances = neighborDistances.Select(p => new {p.index, distance = maxDistance - p.distance}).ToList(); neighborDistances.Sort((a, b) => b.distance.CompareTo(a.distance)); var totalDistance = neighborDistances.Sum(p => p.distance); var threshold = random.NextDouble()*totalDistance; var sum = 0d; var index = 0; while (index < neighborDistances.Count && sum < threshold) { sum += neighborDistances[index].distance; index++; } index = Math.Min(index, neighborDistances.Count - 1); return neighborDistances[index].index; } } }