Free cookie consent management tool by TermsFeed Policy Generator

source: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/LogisticCostEvaluator.cs @ 17777

Last change on this file since 17777 was 16575, checked in by gkronber, 5 years ago

#2520: changed HeuristicLab.BioBoost addon to compile with new HL.Persistence

File size: 11.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using HeuristicLab.BioBoost.Data;
23using HeuristicLab.BioBoost.ProblemDescription;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using HeuristicLab.Data;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using HeuristicLab.BioBoost.Representation;
32using HeuristicLab.BioBoost.Utils;
33using HEAL.Attic;
34
35namespace HeuristicLab.BioBoost.Evaluators {
36  [StorableType("C633F527-7C12-478D-AECA-00D3E54ED2D2")]
37  public class LogisticCostEvaluator : BioBoostEvaluator {
38
39    private class Variant : IComparable<Variant> {
40      public double HandlingCost;
41      public double TransportCost;
42      public double Penalty;
43      public double Distance;
44      public Logistic Logistic;
45      public double Amount;
46      public int CompareTo(Variant other) {
47        return (int)((HandlingCost + TransportCost) - (other.HandlingCost + other.TransportCost));
48      }
49    }
50
51    #region fields
52    private DoubleArray invest, maint, fuel, labor, other;
53    #endregion
54
55    #region Construction & Cloning
56    [StorableConstructor]
57    protected LogisticCostEvaluator(StorableConstructorFlag _) : base(_) { }
58
59    protected LogisticCostEvaluator(LogisticCostEvaluator original, Cloner cloner) : base(original, cloner) {}
60
61    public LogisticCostEvaluator() { }
62
63    public override IDeepCloneable Clone(Cloner cloner) {
64      return new LogisticCostEvaluator(this, cloner);
65    }
66    #endregion
67
68    public override IOperation Apply() {
69      var logistics = ProblemData.Logistics;
70      var distances = new Dictionary<string, DistanceMatrix>();
71      var emissions = new Dictionary<string, DoubleArray>();
72      invest = ProblemData.InvestmentCostFactors;
73      maint = ProblemData.MaintenanceCostFactors;
74      fuel = ProblemData.FuelCostFactors;
75      labor = ProblemData.LaborCostFactors;
76      other = ProblemData.OtherCostFactors;
77      var prices = ProblemData.Products.ToDictionary(p => p.Label, p => p.Price); // TODO: regional scaling for supplies and side-products?
78      foreach (var product in logistics.Select(l => l.Key)) {
79        var amountsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtSource.NameWithPrefix(product));
80        var costsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(product));
81        var transportTargets = GetFromScope<IntArray>(LayerDescriptor.TransportTargets.NameWithPrefix(product));
82        if (amountsAtSource == null || transportTargets == null) continue;
83        var length = amountsAtSource.Length;
84        var sources = new ItemArray<ItemList<IntValue>>(length);
85        var amountsAtTarget = new DoubleArray(length);
86        var chosenVariants = new List<Variant>(new Variant[length]);
87        var costsAtTarget = new DoubleArray(length);
88        var totalProductHandlingCost = 0d;
89        var totalProductTransportCost = 0d;
90        var totalPenalty = 0d;
91        for (int i = 0; i < length; i++) {
92          var amount = amountsAtSource[i];
93          if (amount <= 0) continue;
94          var j = transportTargets[i];
95          if (j == -1) {
96            amountsAtSource[i] = 0; // no transport -> no feedstock collected
97            continue;
98          }
99          var chosenVariant = ChooseVariant(logistics[product], amount, i, j, distances);
100          if (chosenVariant != null) {
101            amountsAtTarget[j] += Math.Min(chosenVariant.Amount, amount); // cannot have more than before
102            costsAtTarget[j] += costsAtSource[i] + chosenVariant.HandlingCost + chosenVariant.TransportCost +
103                                chosenVariant.Logistic.Transport.Emissions.TotalCost(prices, null)*chosenVariant.Amount*chosenVariant.Distance +
104                                chosenVariant.Logistic.Handling.Emissions.TotalCost(prices, null)*chosenVariant.Amount;
105            totalProductHandlingCost += chosenVariant.HandlingCost;
106            totalProductTransportCost += chosenVariant.TransportCost;
107            totalPenalty += chosenVariant.Penalty;
108            AddEmissions(emissions, chosenVariant.Logistic.Handling.Emissions, amount, i, j, length);
109            AddEmissions(emissions, chosenVariant.Logistic.Transport.Emissions, amount*chosenVariant.Distance, i, j, length);
110            chosenVariants[i] = chosenVariant;
111            if (sources[j] != null) {
112              sources[j].Add(new IntValue(i));
113            } else {
114              sources[j] = new ItemList<IntValue>(new [] { new IntValue(i) });
115            }
116          } else {
117            amountsAtSource[i] = 0; // will be AmountsTransportedFromSource
118          }
119        }
120        RenameInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(product), LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(product));
121        PutInScope(LayerDescriptor.TransportModes.NameWithPrefix(product), chosenVariants.Select("", v => v.Logistic.Mode).ToStringArray(), false);
122        PutInScope(LayerDescriptor.TransportCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.TransportCost).ToDoubleArray(), false);
123        PutInScope(LayerDescriptor.TransportCostsPerT.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : v.TransportCost / v.Amount).ToDoubleArray(), false);
124        PutInScope(LayerDescriptor.TransportCostsPerTkm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 || v.Distance == 0 ? 0 : v.TransportCost / v.Amount / v.Distance).ToDoubleArray(), false);
125        PutInScope(LayerDescriptor.HandlingCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.HandlingCost).ToDoubleArray(), false);
126        PutInScope(LayerDescriptor.RelativeHandlingCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : v.HandlingCost / v.Amount).ToDoubleArray(), false);
127        AddInScope(LayerDescriptor.AmountsAtTarget.NameWithPrefix(product), amountsAtTarget, false);
128        AddInScope(LayerDescriptor.TotalCostsAtTarget.NameWithPrefix(product), costsAtTarget, false);
129        PutInScope(LayerDescriptor.RelativeCostAtTarget.NameWithPrefix(product), costsAtTarget.Zip(amountsAtTarget, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
130        PutInScope(LayerDescriptor.TransportDistance.NameWithPrefix(product), chosenVariants.Select(0, v => v.Distance).ToDoubleArray(), false);
131        PutInScope(LayerDescriptor.Tkm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Distance*v.Amount).ToDoubleArray(), false);
132        var transportPenalties = chosenVariants.Select(0, v => v.Penalty).ToDoubleArray();
133        PutInScope(LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(product), transportPenalties, false);
134        AddInScope(LayerDescriptor.TotalPenalty.Name, (DoubleArray)transportPenalties.Clone(), false);
135        PutInScope(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.TransportCost + v.HandlingCost).ToDoubleArray(), false);
136        PutInScope(LayerDescriptor.LogisticCostsPerTon.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : (v.TransportCost + v.HandlingCost)/v.Amount).ToDoubleArray(), false);
137        //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);
138        AddInScope(LayerDescriptor.LocalAddedValue.Name, chosenVariants.Select(0, v => v.HandlingCost + v.TransportCost).ToDoubleArray(), false);
139        PutInScope(LayerDescriptor.Sources.NameWithPrefix(product), sources, false);
140        AddCost(LayerDescriptor.HandlingCosts.NameWithPrefix(product), totalProductHandlingCost);
141        AddCost(LayerDescriptor.TransportCosts.NameWithPrefix(product), totalProductTransportCost);
142        AddCost(LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(product), totalPenalty);
143      }
144      foreach (var e in emissions) {
145        AddInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(e.Key), e.Value, false);
146        AddInScope(LayerDescriptor.DischargeCosts.NameWithPrefix(e.Key), e.Value.Select(x => !prices.ContainsKey(e.Key) ? 0 : (prices[e.Key] * x)).ToDoubleArray(), false);
147      }
148      return base.Apply();
149    }
150
151    private Variant ChooseVariant(IEnumerable<Logistic> logistics, double amount, int i, int j, IDictionary<string, DistanceMatrix> distances) {
152      var variants = new List<Variant>();
153      foreach (var l in logistics) {
154        DistanceMatrix distanceMatrix = null;
155        if (!distances.TryGetValue(l.Distances, out distanceMatrix)) {
156          distanceMatrix = GetFromProblemData<DistanceMatrix>(l.Distances + "DistanceMatrix");
157          if (distanceMatrix != null)
158            distances[l.Distances] = distanceMatrix;
159          else
160            throw new InvalidOperationException("Distance Matrix \"" + l.Distances +
161              "\" for logistic action \"" + l.Mode +
162              "\" of product \"" + l.Product + "\" could not be loaded");
163        }
164        if (distanceMatrix == null) continue;
165        var distance = distanceMatrix[i, j];
166        var actualAmount = Math.Min(Math.Max(amount, l.MinAmount), l.MaxAmount);
167        var v = new Variant {
168          Amount = actualAmount,
169          Logistic = l,
170          HandlingCost = GetLogisticActionCost(l.Handling, actualAmount*(1-l.WaterContent), i, j),
171          TransportCost = GetLogisticActionCost(l.Transport, actualAmount*distance*(1-l.WaterContent), i, j),
172          Distance = distance
173        };
174        if (distance > l.MaxDistance)
175          v.Penalty = Penalty(distance, l.MaxDistance, distanceMatrix.Max);
176        variants.Add(v);
177      }
178      variants.Sort();
179      return variants.FirstOrDefault();
180    }
181
182    public static double Penalty(double distance, double maxAllowedDistance, double maxPossibleDistance) {
183      return (distance - maxAllowedDistance)/maxPossibleDistance;
184    }
185
186    private double GetLogisticActionCost(LogisticAction a, double amount, int i, int j) {
187      return
188        amount * (
189          a.Investment  *(invest[i] + invest[j]) +
190          a.Maintenance *( maint[i] +  maint[j]) +
191          a.Fuel        *(  fuel[i] +   fuel[j]) +
192          a.Labor       *( labor[i] +  labor[j]) +
193          a.Other       *( other[i] +  other[j]))/2;
194    }
195
196    private void AddEmissions(Dictionary<string, DoubleArray> totalEmissions, IEnumerable<IValueParameter> emissions, double amount, int i, int j, int length) {
197      foreach (var e in emissions) {
198        DoubleArray values = null;
199        if (!totalEmissions.TryGetValue(e.Name, out values)) {
200          totalEmissions.Add(e.Name, values = new DoubleArray(length));
201        }
202        values[i] += ((DoubleValue)e.Value).Value*amount/2;
203        values[j] += ((DoubleValue)e.Value).Value*amount/2;
204      }
205    }
206  }
207}
Note: See TracBrowser for help on using the repository browser.