[10264] | 1 | using System;
|
---|
| 2 | using System.Collections.Generic;
|
---|
| 3 | using System.Linq;
|
---|
| 4 | using HeuristicLab.Common;
|
---|
| 5 | using HeuristicLab.Core;
|
---|
| 6 | using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
|
---|
| 7 | using HeuristicLab.Operators;
|
---|
| 8 | using HeuristicLab.Optimization;
|
---|
| 9 | using HeuristicLab.Parameters;
|
---|
| 10 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
| 11 | using HeuristicLab.Problems.DataAnalysis.Symbolic;
|
---|
| 12 |
|
---|
| 13 | using GeneticExchangeMapType = HeuristicLab.Core.IItemList<HeuristicLab.Core.IItem>;
|
---|
| 14 |
|
---|
| 15 | namespace HeuristicLab.EvolutionaryTracking.Operators {
|
---|
| 16 | [Item("SymbolicExpressionTreeSymbolGraphBuilder", "An operator that builds a graph of pair-wise symbol relationships from the trees in the population.")]
|
---|
| 17 | [StorableClass]
|
---|
| 18 | class SymbolicExpressionTreeSymbolGraphBuilder : SingleSuccessorOperator {
|
---|
| 19 | #region Parameter names
|
---|
| 20 | private const string GlobalGeneticExchangeMapParameterName = "GlobalGeneticExchangeMap";
|
---|
| 21 | private const string SymbolicExpressionTreeParameterName = "SymbolicExpressionTree";
|
---|
| 22 | private const string ResultsParameterName = "Results";
|
---|
| 23 | #endregion
|
---|
| 24 | #region Parameter properties
|
---|
| 25 | public ILookupParameter<GeneticExchangeMapType> GlobalGeneticExchangeMapParameter {
|
---|
| 26 | get { return (LookupParameter<GeneticExchangeMapType>)Parameters[GlobalGeneticExchangeMapParameterName]; }
|
---|
| 27 | }
|
---|
| 28 | #endregion
|
---|
| 29 | #region Properties
|
---|
| 30 | public GeneticExchangeMapType GlobalGeneticExchangeMap {
|
---|
| 31 | get { return GlobalGeneticExchangeMapParameter.ActualValue; }
|
---|
| 32 | }
|
---|
| 33 | #endregion
|
---|
| 34 |
|
---|
| 35 | [StorableConstructor]
|
---|
| 36 | private SymbolicExpressionTreeSymbolGraphBuilder(bool deserializing) : base(deserializing) { }
|
---|
| 37 | private SymbolicExpressionTreeSymbolGraphBuilder(SymbolicExpressionTreeSymbolGraphBuilder original, Cloner cloner) : base(original, cloner) { }
|
---|
| 38 | public override IDeepCloneable Clone(Cloner cloner) { return new SymbolicExpressionTreeSymbolGraphBuilder(this, cloner); }
|
---|
| 39 | public SymbolicExpressionTreeSymbolGraphBuilder() {
|
---|
| 40 | Parameters.Add(new ScopeTreeLookupParameter<ISymbolicExpressionTree>(SymbolicExpressionTreeParameterName, "The symbolic expression trees to analyze."));
|
---|
| 41 | Parameters.Add(new LookupParameter<GeneticExchangeMapType>(GlobalGeneticExchangeMapParameterName, "Global map of genetic exchanges."));
|
---|
| 42 | Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should be stored."));
|
---|
| 43 | }
|
---|
| 44 | #region Parameters
|
---|
| 45 | public IScopeTreeLookupParameter<ISymbolicExpressionTree> SymbolicExpressionTreeParameter {
|
---|
| 46 | get { return (IScopeTreeLookupParameter<ISymbolicExpressionTree>)Parameters[SymbolicExpressionTreeParameterName]; }
|
---|
| 47 | }
|
---|
| 48 | public ILookupParameter<ResultCollection> ResultsParameter {
|
---|
| 49 | get { return (LookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
|
---|
| 50 | }
|
---|
| 51 | #endregion
|
---|
| 52 |
|
---|
| 53 | [StorableHook(HookType.AfterDeserialization)]
|
---|
| 54 | private void AfterDeserialization() {
|
---|
| 55 | if (!Parameters.ContainsKey(ResultsParameterName))
|
---|
| 56 | Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should be stored."));
|
---|
| 57 | if (!Parameters.ContainsKey(GlobalGeneticExchangeMapParameterName))
|
---|
| 58 | Parameters.Add(new LookupParameter<GeneticExchangeMapType>(GlobalGeneticExchangeMapParameterName, "Global map of genetic exchanges."));
|
---|
| 59 | }
|
---|
| 60 | public override IOperation Apply() {
|
---|
| 61 | if (!Parameters.ContainsKey("Results")) return base.Apply();
|
---|
| 62 |
|
---|
| 63 | var trees = SymbolicExpressionTreeParameter.ActualValue.ToList();
|
---|
| 64 |
|
---|
| 65 | var results = ResultsParameter.ActualValue;
|
---|
| 66 |
|
---|
| 67 | // if (!results.ContainsKey("SymbolGraph")) {
|
---|
| 68 | // var graph = CreateSymbolGraph(trees);
|
---|
| 69 | // results.Add(new Result("SymbolGraph", graph));
|
---|
| 70 | // } else {
|
---|
| 71 | // var graph = results["SymbolGraph"].Value as SymbolGraph;
|
---|
| 72 | // var transactions = GlobalGeneticExchangeMap.Select(t => t as GeneticExchange);
|
---|
| 73 | // UpdateGraph(graph, transactions);
|
---|
| 74 | // }
|
---|
| 75 |
|
---|
| 76 | var graph = CreateSymbolGraph(trees);
|
---|
| 77 | if (!results.ContainsKey("SymbolGraph")) {
|
---|
| 78 | results.Add(new Result("SymbolGraph", graph));
|
---|
| 79 | } else {
|
---|
| 80 | results["SymbolGraph"].Value = graph;
|
---|
| 81 | }
|
---|
| 82 |
|
---|
| 83 | return base.Apply();
|
---|
| 84 | }
|
---|
| 85 | private SymbolGraph CreateSymbolGraph(IEnumerable<ISymbolicExpressionTree> trees) {
|
---|
| 86 | var list = trees as IList<ISymbolicExpressionTree> ?? trees.ToList();
|
---|
| 87 |
|
---|
| 88 | var nodes = list.SelectMany(x => x.Root.GetSubtree(0).GetSubtree(0).IterateNodesBreadth()).ToList();
|
---|
| 89 | var graph = new SymbolGraph();
|
---|
| 90 |
|
---|
| 91 | #region create symbol graph
|
---|
| 92 | foreach (var node in nodes) {
|
---|
| 93 | var nodeLabel = node.Label();
|
---|
| 94 | if (!graph.ContainsKey(nodeLabel)) {
|
---|
| 95 | graph.AddNode(new SymbolNode { Label = nodeLabel, Symbol = node.Symbol, Weight = 1.0, AverageArity = node.SubtreeCount });
|
---|
| 96 | } else {
|
---|
| 97 | double avgArity = graph.GetNode(nodeLabel).AverageArity;
|
---|
| 98 | double weight = graph.GetNode(nodeLabel).Weight;
|
---|
| 99 | graph.GetNode(nodeLabel).AverageArity = (avgArity * weight + node.SubtreeCount) / (weight + 1);
|
---|
| 100 | graph.GetNode(nodeLabel).Weight += 1.0;
|
---|
| 101 | }
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | foreach (var node in nodes) {
|
---|
| 105 | var n = graph.GetNode(node.Symbol.Name);
|
---|
| 106 | for (int i = 0; i != node.SubtreeCount; ++i) {
|
---|
| 107 | var child = node.GetSubtree(i);
|
---|
| 108 | var c = graph.GetNode(child.Label());
|
---|
| 109 |
|
---|
| 110 | if (n == null || c == null)
|
---|
| 111 | throw new Exception("The node couldn't be found in the graph."); // should never happen
|
---|
| 112 |
|
---|
| 113 | if (n.OutEdges == null) {
|
---|
| 114 | n.AddForwardArc(c, 1.0);
|
---|
| 115 | } else {
|
---|
| 116 | var arc = n.OutEdges.Find(x => x.Target == c);
|
---|
| 117 | if (arc == null) n.AddForwardArc(c, 1);
|
---|
| 118 | else arc.Weight += 1.0;
|
---|
| 119 | }
|
---|
| 120 | if (c.Positions == null) {
|
---|
| 121 | c.Positions = new Dictionary<int, int> { { i, 1 } };
|
---|
| 122 | } else if (c.Positions.ContainsKey(i)) {
|
---|
| 123 | c.Positions[i] += 1;
|
---|
| 124 | } else {
|
---|
| 125 | c.Positions.Add(i, 1);
|
---|
| 126 | }
|
---|
| 127 | }
|
---|
| 128 | }
|
---|
| 129 | #endregion
|
---|
| 130 |
|
---|
| 131 | return graph;
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | private static void UpdateGraph(SymbolGraph graph, IEnumerable<GeneticExchange> exchanges) {
|
---|
| 135 | // we have the graph, and we have the list of genetic exchanges which allows us to update graph vertex and arc weights
|
---|
| 136 | exchanges = exchanges as IList<GeneticExchange> ?? exchanges.ToList();
|
---|
| 137 | var inFragments = exchanges.Select(t => t.FragmentIn).ToList();
|
---|
| 138 | var outFragments = exchanges.Select(t => t.FragmentOut).ToList();
|
---|
| 139 |
|
---|
| 140 | // the idea is to add to the symbol graph everything that goes in (inFragments) and
|
---|
| 141 | // subtract everything that goes out (outFragments)
|
---|
| 142 |
|
---|
| 143 | // might not be 100% correct because the trees change as well
|
---|
| 144 |
|
---|
| 145 | foreach (var f in inFragments) {
|
---|
| 146 | foreach (var node in f.Root.IterateNodesPrefix()) {
|
---|
| 147 | var parentLabel = node.Label();
|
---|
| 148 | var parentVertex = graph.GetNode(parentLabel);
|
---|
| 149 | if (parentVertex == null) { // highly unlikely but it is possible
|
---|
| 150 | graph.AddNode(new SymbolNode { Label = parentLabel, Symbol = node.Symbol, Weight = 1.0, AverageArity = node.SubtreeCount });
|
---|
| 151 | parentVertex = graph.GetNode(parentLabel);
|
---|
| 152 | } else {
|
---|
| 153 | parentVertex.Weight++;
|
---|
| 154 | }
|
---|
| 155 |
|
---|
| 156 | for (int i = 0; i != node.SubtreeCount; ++i) {
|
---|
| 157 | var child = node.GetSubtree(i);
|
---|
| 158 | var childLabel = child.Label();
|
---|
| 159 | var childVertex = graph.GetNode(childLabel);
|
---|
| 160 |
|
---|
| 161 | if (childVertex == null) { // highly unlikely but it is possible
|
---|
| 162 | graph.AddNode(new SymbolNode { Label = childLabel, Symbol = child.Symbol, Weight = 1.0, AverageArity = node.SubtreeCount });
|
---|
| 163 | childVertex = graph.GetNode(childLabel);
|
---|
| 164 | }
|
---|
| 165 |
|
---|
| 166 | if (parentVertex.OutEdges == null)
|
---|
| 167 | parentVertex.AddForwardArc(childVertex, 1.0);
|
---|
| 168 | else {
|
---|
| 169 | var arc = parentVertex.OutEdges.Find(x => x.Target == childVertex);
|
---|
| 170 | if (arc == null) childVertex.AddForwardArc(childVertex, 1.0);
|
---|
| 171 | else arc.Weight += 1.0;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | if (childVertex.Positions == null) {
|
---|
| 175 | childVertex.Positions = new Dictionary<int, int> { { i, 1 } };
|
---|
| 176 | } else if (childVertex.Positions.ContainsKey(i)) {
|
---|
| 177 | childVertex.Positions[i] += 1;
|
---|
| 178 | } else {
|
---|
| 179 | childVertex.Positions.Add(i, 1);
|
---|
| 180 | }
|
---|
| 181 | }
|
---|
| 182 | }
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 | foreach (var f in outFragments) {
|
---|
| 186 | foreach (var node in f.Root.IterateNodesPrefix()) {
|
---|
| 187 | var parentLabel = node.Label();
|
---|
| 188 | var parentVertex = graph.GetNode(parentLabel);
|
---|
| 189 | if (parentVertex == null)
|
---|
| 190 | throw new ArgumentException("parentVertex for node in outFragment can (should) not be null!");
|
---|
| 191 |
|
---|
| 192 | parentVertex.Weight--;
|
---|
| 193 |
|
---|
| 194 | for (int i = 0; i != node.SubtreeCount; ++i) {
|
---|
| 195 | var child = node.GetSubtree(i);
|
---|
| 196 | var childVertex = graph.GetNode(child.Label());
|
---|
| 197 | if (childVertex == null)
|
---|
| 198 | throw new ArgumentException("childVertex for node in outFragment can (should) not be null!");
|
---|
| 199 |
|
---|
| 200 | // childVertex.Weight--;
|
---|
| 201 |
|
---|
| 202 | var arc = parentVertex.OutEdges.Find(x => x.Target == childVertex);
|
---|
| 203 | if (arc == null)
|
---|
| 204 | throw new Exception("An arc should already exist between the parent and the child.");
|
---|
| 205 |
|
---|
| 206 | arc.Weight -= 1.0;
|
---|
| 207 |
|
---|
| 208 | if (arc.Weight < 0.0)
|
---|
| 209 | throw new ArgumentException("Weight cannot be negative!");
|
---|
| 210 | }
|
---|
| 211 | }
|
---|
| 212 | }
|
---|
| 213 | }
|
---|
| 214 |
|
---|
| 215 | private static void NormalizeGraph(SymbolGraph graph) {
|
---|
| 216 | var nodes = graph.Nodes;
|
---|
| 217 | var sum = nodes.Sum(n => n.Weight);
|
---|
| 218 | foreach (var n in nodes) {
|
---|
| 219 | n.Weight /= sum;
|
---|
| 220 | if (n.OutEdges == null || n.OutEdges.Count <= 0) continue;
|
---|
| 221 | var arcSum = n.OutEdges.Sum(arc => arc.Weight);
|
---|
| 222 | foreach (var arc in n.OutEdges)
|
---|
| 223 | arc.Weight /= arcSum;
|
---|
| 224 | }
|
---|
| 225 | }
|
---|
| 226 | private static void PruneGraph(SymbolGraph graph) {
|
---|
| 227 | var arcs = graph.Nodes.Where(node => node.OutEdges != null).SelectMany(node => node.OutEdges).ToList();
|
---|
| 228 | var arcWeights = arcs.Select(arc => arc.Weight).ToList();
|
---|
| 229 | var median = arcWeights.Median();
|
---|
| 230 | foreach (var node in graph.Nodes.Where(n => n.OutEdges != null)) {
|
---|
| 231 | node.OutEdges.RemoveAll(arc => arc.Weight < median || ((SymbolNode)arc.Target).Symbol is Constant);
|
---|
| 232 | node.OutEdges.RemoveAll(arc => arc.Weight < median);
|
---|
| 233 | }
|
---|
| 234 | }
|
---|
| 235 | }
|
---|
| 236 | }
|
---|