source: branches/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/SolutionSpaceDiscoverer.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: 5.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using HeuristicLab.BioBoost.Data;
6using HeuristicLab.Core;
7using HeuristicLab.Data;
8using SharpMap.Data;
9
10namespace HeuristicLab.BioBoost.ProblemDescription {
11  public class SolutionSpaceDiscoverer {
12
13    private enum ProductCheck { None, NonFeasible, InProgress, Feasible };
14
15    // caches
16    private readonly List<Product> products;
17    private readonly HashSet<string> transportableProductNames;
18    private readonly List<Conversion> conversions;
19    private readonly Dictionary<string, double> prices;
20    private readonly Dictionary<Product, List<Conversion>> choices; 
21
22    // status
23    private readonly Dictionary<Product, ProductCheck> currentChecks;
24
25    // results
26    public List<string> FeasibleFeedstocks { get; private set; }
27    public List<string> FeasibleTransports { get; private set; }
28    public Dictionary<string, List<string>> FeasibleChoices { get; private set; }
29    public Dictionary<string, string> FeasibilityAnalysis { get; private set; }
30    public int MaxDepth { get; private set; }
31
32    public SolutionSpaceDiscoverer(IEnumerable<string> feedstockNames, List<Product> products, IEnumerable<Logistic> logistics, IEnumerable<Conversion> conversions) {
33      this.products = products.ToList();
34      transportableProductNames = new HashSet<string>();
35      foreach (var l in logistics) {
36        transportableProductNames.Add(l.Product);
37      }
38      this.conversions = conversions.ToList();
39      this.prices = products.ToDictionary(p => p.Label, p => p.Price);
40      this.choices = new Dictionary<Product, List<Conversion>>();
41
42      this.currentChecks = products.ToDictionary(p => p, p => ProductCheck.None);
43
44      this.FeasibilityAnalysis = products.ToDictionary(p => p.Label, p => string.Empty);
45      this.FeasibleFeedstocks = new List<string>();
46      this.FeasibleTransports = new List<string>();
47      this.MaxDepth = 0;
48      var feedstocks = new HashSet<string>(feedstockNames);
49      var feedstockProducts = products.Where(p => feedstocks.Contains(p.Label)).ToList();
50      foreach (var input in feedstockProducts) {
51        if (CheckProduct(input)) {
52          FeasibleFeedstocks.Add(input.Label);
53        }
54      }
55      foreach (var pair in currentChecks) {
56        if (pair.Value == ProductCheck.Feasible) {
57          FeasibleTransports.Add(pair.Key.Label);
58          List<Conversion> newChoices = null;
59          if (choices.TryGetValue(pair.Key, out newChoices)) {
60            FeasibleChoices.Add(pair.Key.Label, newChoices.Select(c => c.Label).ToList());
61          }
62        }
63      }
64    }
65
66    public SolutionSpaceDiscoverer(IEnumerable<string> feedstockNames, List<DataItem> dataItems)
67      : this(feedstockNames, dataItems.OfType<Product>().ToList(), dataItems.OfType<Logistic>(), dataItems.OfType<Conversion>()) {}
68
69
70    private bool CheckProduct(Product inputProduct, int currentDepth = 1) {
71
72      switch (currentChecks[inputProduct]) {
73        case ProductCheck.Feasible:
74          return true;
75        case ProductCheck.NonFeasible:
76          return false;
77        case ProductCheck.InProgress:
78          FeasibilityAnalysis[inputProduct.Label] += "not checked recursively: circular dependency";
79          return false;
80        case ProductCheck.None:
81          break;
82      }
83      currentChecks[inputProduct] = ProductCheck.InProgress;
84
85      // transportable?
86      if (!transportableProductNames.Contains(inputProduct.Label)) {
87        currentChecks[inputProduct] = ProductCheck.NonFeasible;
88        FeasibilityAnalysis[inputProduct.Label] += "NOT transportable";
89        return false; // not transportable
90      }
91
92      // convertable?
93      var otherOutputProducts = new HashSet<Product>();
94      var profitableOutputProducts = new HashSet<Product>();
95      var profitableConversions = new List<Conversion>();
96      foreach (var c in conversions.Where(c => c.Feedstock == inputProduct.Label)) {
97
98        // outputs?
99        foreach (var outputProductParameter in c.Products) {
100          var outputProductName = outputProductParameter.Name;
101          var outputAmount = outputProductParameter.Value as DoubleValue;
102          if (string.IsNullOrEmpty(outputProductName))
103            continue; // no product
104          var product = products.FirstOrDefault(p2 => p2.Label == outputProductName);
105          if (product == null || outputAmount == null)
106            continue; // not a real product
107          double amount = outputAmount.Value;
108          double price;
109          if (prices.TryGetValue(product.Label, out price) && price*amount > 0) {
110            profitableOutputProducts.Add(product);
111          } else {
112            otherOutputProducts.Add(product);
113          }
114        }
115        // recurse
116        foreach (var p in profitableOutputProducts)
117          CheckProduct(p, currentDepth + 1);
118        var otherProfits = otherOutputProducts.Any(p => CheckProduct(p, currentDepth + 1));
119
120        // analyze
121        if (profitableOutputProducts.Count == 0 && !otherProfits) {
122          currentChecks[inputProduct] = ProductCheck.NonFeasible;
123          FeasibilityAnalysis[inputProduct.Label] += "NO profitable direct or indirect output products";
124        } else {
125          currentChecks[inputProduct] = ProductCheck.Feasible;
126          MaxDepth = Math.Max(MaxDepth, currentDepth);
127          profitableConversions.Add(c);
128          if (profitableOutputProducts.Count > 0) FeasibilityAnalysis[inputProduct.Label] += "profitable direct output products ";
129          if (otherProfits) FeasibilityAnalysis[inputProduct.Label] += "profitable indirect output products";
130        }
131      }
132
133      // conclusion
134      if (profitableConversions.Count > 1)
135        choices.Add(inputProduct, profitableConversions);
136      return profitableConversions.Count > 0;
137    }
138  }
139}
Note: See TracBrowser for help on using the repository browser.