source: branches/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/LogisticCostEvaluator.cs @ 13069

Last change on this file since 13069 was 13069, checked in by gkronber, 7 years ago

#2499: imported source code for HeuristicLab.BioBoost from private repository with some changes

File size: 10.7 KB
Line 
1using HeuristicLab.BioBoost.Data;
2using HeuristicLab.BioBoost.ProblemDescription;
3using HeuristicLab.Common;
4using HeuristicLab.Core;
5using HeuristicLab.Data;
6using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
7using System;
8using System.Collections.Generic;
9using System.Linq;
10using HeuristicLab.BioBoost.Representation;
11using HeuristicLab.BioBoost.Utils;
12
13namespace HeuristicLab.BioBoost.Evaluators {
14  [StorableClass]
15  public class LogisticCostEvaluator : BioBoostEvaluator {
16
17    private class Variant : IComparable<Variant> {
18      public double HandlingCost;
19      public double TransportCost;
20      public double Penalty;
21      public double Distance;
22      public Logistic Logistic;
23      public double Amount;
24      public int CompareTo(Variant other) {
25        return (int)((HandlingCost + TransportCost) - (other.HandlingCost + other.TransportCost));
26      }
27    }
28
29    #region fields
30    private DoubleArray invest, maint, fuel, labor, other;
31    #endregion
32
33    #region Construction & Cloning
34    [StorableConstructor]
35    protected LogisticCostEvaluator(bool isDeserializing) : base(isDeserializing) {}
36
37    protected LogisticCostEvaluator(LogisticCostEvaluator original, Cloner cloner) : base(original, cloner) {}
38
39    public LogisticCostEvaluator() { }
40
41    public override IDeepCloneable Clone(Cloner cloner) {
42      return new LogisticCostEvaluator(this, cloner);
43    }
44    #endregion
45
46    public override IOperation Apply() {
47      var logistics = ProblemData.Logistics;
48      var distances = new Dictionary<string, DistanceMatrix>();
49      var emissions = new Dictionary<string, DoubleArray>();
50      invest = ProblemData.InvestmentCostFactors;
51      maint = ProblemData.MaintenanceCostFactors;
52      fuel = ProblemData.FuelCostFactors;
53      labor = ProblemData.LaborCostFactors;
54      other = ProblemData.OtherCostFactors;
55      var prices = ProblemData.Products.ToDictionary(p => p.Label, p => p.Price); // TODO: regional scaling for supplies and side-products?
56      foreach (var product in logistics.Select(l => l.Key)) {
57        var amountsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtSource.NameWithPrefix(product));
58        var costsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(product));
59        var transportTargets = GetFromScope<IntArray>(LayerDescriptor.TransportTargets.NameWithPrefix(product));
60        if (amountsAtSource == null || transportTargets == null) continue;
61        var length = amountsAtSource.Length;
62        var sources = new ItemArray<ItemList<IntValue>>(length);
63        var amountsAtTarget = new DoubleArray(length);
64        var chosenVariants = new List<Variant>(new Variant[length]);
65        var costsAtTarget = new DoubleArray(length);
66        var totalProductHandlingCost = 0d;
67        var totalProductTransportCost = 0d;
68        var totalPenalty = 0d;
69        for (int i = 0; i < length; i++) {
70          var amount = amountsAtSource[i];
71          if (amount <= 0) continue;
72          var j = transportTargets[i];
73          if (j == -1) {
74            amountsAtSource[i] = 0; // no transport -> no feedstock collected
75            continue;
76          }
77          var chosenVariant = ChooseVariant(logistics[product], amount, i, j, distances);
78          if (chosenVariant != null) {
79            amountsAtTarget[j] += Math.Min(chosenVariant.Amount, amount); // cannot have more than before
80            costsAtTarget[j] += costsAtSource[i] + chosenVariant.HandlingCost + chosenVariant.TransportCost +
81                                chosenVariant.Logistic.Transport.Emissions.TotalCost(prices, null)*chosenVariant.Amount*chosenVariant.Distance +
82                                chosenVariant.Logistic.Handling.Emissions.TotalCost(prices, null)*chosenVariant.Amount;
83            totalProductHandlingCost += chosenVariant.HandlingCost;
84            totalProductTransportCost += chosenVariant.TransportCost;
85            totalPenalty += chosenVariant.Penalty;
86            AddEmissions(emissions, chosenVariant.Logistic.Handling.Emissions, amount, i, j, length);
87            AddEmissions(emissions, chosenVariant.Logistic.Transport.Emissions, amount*chosenVariant.Distance, i, j, length);
88            chosenVariants[i] = chosenVariant;
89            if (sources[j] != null) {
90              sources[j].Add(new IntValue(i));
91            } else {
92              sources[j] = new ItemList<IntValue>(new [] { new IntValue(i) });
93            }
94          } else {
95            amountsAtSource[i] = 0; // will be AmountsTransportedFromSource
96          }
97        }
98        RenameInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(product), LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(product));
99        PutInScope(LayerDescriptor.TransportModes.NameWithPrefix(product), chosenVariants.Select("", v => v.Logistic.Mode).ToStringArray(), false);
100        PutInScope(LayerDescriptor.TransportCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.TransportCost).ToDoubleArray(), false);
101        PutInScope(LayerDescriptor.TransportCostsPerT.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : v.TransportCost / v.Amount).ToDoubleArray(), false);
102        PutInScope(LayerDescriptor.TransportCostsPerTkm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 || v.Distance == 0 ? 0 : v.TransportCost / v.Amount / v.Distance).ToDoubleArray(), false);
103        PutInScope(LayerDescriptor.HandlingCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.HandlingCost).ToDoubleArray(), false);
104        PutInScope(LayerDescriptor.RelativeHandlingCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : v.HandlingCost / v.Amount).ToDoubleArray(), false);
105        AddInScope(LayerDescriptor.AmountsAtTarget.NameWithPrefix(product), amountsAtTarget, false);
106        AddInScope(LayerDescriptor.TotalCostsAtTarget.NameWithPrefix(product), costsAtTarget, false);
107        PutInScope(LayerDescriptor.RelativeCostAtTarget.NameWithPrefix(product), costsAtTarget.Zip(amountsAtTarget, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
108        PutInScope(LayerDescriptor.TransportDistance.NameWithPrefix(product), chosenVariants.Select(0, v => v.Distance).ToDoubleArray(), false);
109        PutInScope(LayerDescriptor.Tkm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Distance*v.Amount).ToDoubleArray(), false);
110        var transportPenalties = chosenVariants.Select(0, v => v.Penalty).ToDoubleArray();
111        PutInScope(LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(product), transportPenalties, false);
112        AddInScope(LayerDescriptor.TotalPenalty.Name, (DoubleArray)transportPenalties.Clone(), false);
113        PutInScope(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.TransportCost + v.HandlingCost).ToDoubleArray(), false);
114        PutInScope(LayerDescriptor.LogisticCostsPerTon.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : (v.TransportCost + v.HandlingCost)/v.Amount).ToDoubleArray(), false);
115        //PutInScope(LayerDescriptor.LogisticCostsPerTonKm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount * v.Distance == 0 ? 0 : (v.TransportCost + v.HandlingCost)/v.Amount/v.Distance).ToDoubleArray(), false);
116        AddInScope(LayerDescriptor.LocalAddedValue.Name, chosenVariants.Select(0, v => v.HandlingCost + v.TransportCost).ToDoubleArray(), false);
117        PutInScope(LayerDescriptor.Sources.NameWithPrefix(product), sources, false);
118        AddCost(LayerDescriptor.HandlingCosts.NameWithPrefix(product), totalProductHandlingCost);
119        AddCost(LayerDescriptor.TransportCosts.NameWithPrefix(product), totalProductTransportCost);
120        AddCost(LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(product), totalPenalty);
121      }
122      foreach (var e in emissions) {
123        AddInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(e.Key), e.Value, false);
124        AddInScope(LayerDescriptor.DischargeCosts.NameWithPrefix(e.Key), e.Value.Select(x => !prices.ContainsKey(e.Key) ? 0 : (prices[e.Key] * x)).ToDoubleArray(), false);
125      }
126      return base.Apply();
127    }
128
129    private Variant ChooseVariant(IEnumerable<Logistic> logistics, double amount, int i, int j, IDictionary<string, DistanceMatrix> distances) {
130      var variants = new List<Variant>();
131      foreach (var l in logistics) {
132        DistanceMatrix distanceMatrix = null;
133        if (!distances.TryGetValue(l.Distances, out distanceMatrix)) {
134          distanceMatrix = GetFromProblemData<DistanceMatrix>(l.Distances + "DistanceMatrix");
135          if (distanceMatrix != null)
136            distances[l.Distances] = distanceMatrix;
137          else
138            throw new InvalidOperationException("Distance Matrix \"" + l.Distances +
139              "\" for logistic action \"" + l.Mode +
140              "\" of product \"" + l.Product + "\" could not be loaded");
141        }
142        if (distanceMatrix == null) continue;
143        var distance = distanceMatrix[i, j];
144        var actualAmount = Math.Min(Math.Max(amount, l.MinAmount), l.MaxAmount);
145        var v = new Variant {
146          Amount = actualAmount,
147          Logistic = l,
148          HandlingCost = GetLogisticActionCost(l.Handling, actualAmount*(1-l.WaterContent), i, j),
149          TransportCost = GetLogisticActionCost(l.Transport, actualAmount*distance*(1-l.WaterContent), i, j),
150          Distance = distance
151        };
152        if (distance > l.MaxDistance)
153          v.Penalty = Penalty(distance, l.MaxDistance, distanceMatrix.Max);
154        variants.Add(v);
155      }
156      variants.Sort();
157      return variants.FirstOrDefault();
158    }
159
160    public static double Penalty(double distance, double maxAllowedDistance, double maxPossibleDistance) {
161      return (distance - maxAllowedDistance)/maxPossibleDistance;
162    }
163
164    private double GetLogisticActionCost(LogisticAction a, double amount, int i, int j) {
165      return
166        amount * (
167          a.Investment  *(invest[i] + invest[j]) +
168          a.Maintenance *( maint[i] +  maint[j]) +
169          a.Fuel        *(  fuel[i] +   fuel[j]) +
170          a.Labor       *( labor[i] +  labor[j]) +
171          a.Other       *( other[i] +  other[j]))/2;
172    }
173
174    private void AddEmissions(Dictionary<string, DoubleArray> totalEmissions, IEnumerable<IValueParameter> emissions, double amount, int i, int j, int length) {
175      foreach (var e in emissions) {
176        DoubleArray values = null;
177        if (!totalEmissions.TryGetValue(e.Name, out values)) {
178          totalEmissions.Add(e.Name, values = new DoubleArray(length));
179        }
180        values[i] += ((DoubleValue)e.Value).Value*amount/2;
181        values[j] += ((DoubleValue)e.Value).Value*amount/2;
182      }
183    }
184  }
185}
Note: See TracBrowser for help on using the repository browser.