Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
02/11/20 13:36:02 (4 years ago)
Author:
bburlacu
Message:

#1772: Merge trunk changes and fix all errors and compilation warnings.

Location:
branches/1772_HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/1772_HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic

  • branches/1772_HeuristicLab.EvolutionTracking/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeBottomUpSimilarityCalculator.cs

    r16130 r17434  
    22
    33/* HeuristicLab
    4  * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
     4 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
    55 *
    66 * This file is part of HeuristicLab.
     
    2424using System;
    2525using System.Collections.Generic;
    26 using System.Diagnostics;
    2726using System.Globalization;
    2827using System.Linq;
     
    3130using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
    3231using HeuristicLab.Optimization.Operators;
    33 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     32using HEAL.Attic;
     33
     34using NodeMap = System.Collections.Generic.Dictionary<HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ISymbolicExpressionTreeNode, HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ISymbolicExpressionTreeNode>;
    3435
    3536namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
    36 
    37   [StorableClass]
     37  [StorableType("63ACB7A4-137F-468F-BE42-A4CA6B62C63B")]
    3838  [Item("SymbolicExpressionTreeBottomUpSimilarityCalculator", "A similarity calculator which uses the tree bottom-up distance as a similarity metric.")]
    3939  public class SymbolicExpressionTreeBottomUpSimilarityCalculator : SolutionSimilarityCalculator {
     
    4545    protected override bool IsCommutative { get { return true; } }
    4646
     47    public bool MatchConstantValues { get; set; }
    4748    public bool MatchVariableWeights { get; set; }
    48     public bool MatchConstantValues { get; set; }
    4949
    5050    [StorableConstructor]
    51     protected SymbolicExpressionTreeBottomUpSimilarityCalculator(bool deserializing)
    52       : base(deserializing) {
     51    protected SymbolicExpressionTreeBottomUpSimilarityCalculator(StorableConstructorFlag _) : base(_) {
    5352    }
    5453
     
    6160    }
    6261
     62    #region static methods
     63    private static ISymbolicExpressionTreeNode ActualRoot(ISymbolicExpressionTree tree) {
     64      return tree.Root.GetSubtree(0).GetSubtree(0);
     65    }
     66
     67    public static double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, bool strict = false) {
     68      return CalculateSimilarity(ActualRoot(t1), ActualRoot(t2), strict);
     69    }
     70
     71    public static double CalculateSimilarity(ISymbolicExpressionTreeNode n1, ISymbolicExpressionTreeNode n2, bool strict = false) {
     72      var calculator = new SymbolicExpressionTreeBottomUpSimilarityCalculator { MatchConstantValues = strict, MatchVariableWeights = strict };
     73      return CalculateSimilarity(n1, n2, strict);
     74    }
     75
     76    public static Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, bool strict = false) {
     77      return ComputeBottomUpMapping(ActualRoot(t1), ActualRoot(t2), strict);
     78    }
     79
     80    public static Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTreeNode n1, ISymbolicExpressionTreeNode n2, bool strict = false) {
     81      var calculator = new SymbolicExpressionTreeBottomUpSimilarityCalculator { MatchConstantValues = strict, MatchVariableWeights = strict };
     82      return calculator.ComputeBottomUpMapping(n1, n2);
     83    }
     84    #endregion
     85
    6386    public double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
    64       if (t1 == t2)
     87      return CalculateSimilarity(t1, t2, out Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> map);
     88    }
     89
     90    public double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, out NodeMap map) {
     91      if (t1 == t2) {
     92        map = null;
    6593        return 1;
    66 
    67       var map = ComputeBottomUpMapping(t1.Root, t2.Root);
    68       return 2.0 * map.Count / (t1.Length + t2.Length);
     94      }
     95      map = ComputeBottomUpMapping(t1, t2);
     96      return 2.0 * map.Count / (t1.Length + t2.Length - 4); // -4 for skipping root and start symbols in the two trees
    6997    }
    7098
     
    86114    }
    87115
     116    public Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
     117      return ComputeBottomUpMapping(ActualRoot(t1), ActualRoot(t2));
     118    }
     119
    88120    public Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTreeNode n1, ISymbolicExpressionTreeNode n2) {
    89       var comparer = new SymbolicExpressionTreeNodeComparer(); // use a node comparer because it's faster than calling node.ToString() (strings are expensive) and comparing strings
    90121      var compactedGraph = Compact(n1, n2);
    91122
    92       var forwardMap = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t1 => nodes of t2
    93       var reverseMap = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t2 => nodes of t1
    94 
    95       // visit nodes in order of decreasing height to ensure correct mapping
    96       var nodes1 = n1.IterateNodesPrefix().OrderByDescending(x => x.GetDepth()).ToList();
    97       var nodes2 = n2.IterateNodesPrefix().ToList();
    98       for (int i = 0; i < nodes1.Count; ++i) {
    99         var v = nodes1[i];
    100         if (forwardMap.ContainsKey(v))
     123      IEnumerable<ISymbolicExpressionTreeNode> Subtrees(ISymbolicExpressionTreeNode node, bool commutative) {
     124        var subtrees = node.IterateNodesPrefix();
     125        return commutative ? subtrees.OrderBy(x => compactedGraph[x].Hash) : subtrees;
     126      }
     127
     128      var nodes1 = n1.IterateNodesPostfix().OrderByDescending(x => x.GetLength()); // by descending length so that largest subtrees are mapped first
     129      var nodes2 = (List<ISymbolicExpressionTreeNode>)n2.IterateNodesPostfix();
     130
     131      var forward = new NodeMap();
     132      var reverse = new NodeMap();
     133
     134      foreach (ISymbolicExpressionTreeNode v in nodes1) {
     135        if (forward.ContainsKey(v))
    101136          continue;
     137
    102138        var kv = compactedGraph[v];
    103         ISymbolicExpressionTreeNode w = null;
    104         for (int j = 0; j < nodes2.Count; ++j) {
    105           var t = nodes2[j];
    106           if (reverseMap.ContainsKey(t) || compactedGraph[t] != kv)
     139        var commutative = v.SubtreeCount > 1 && commutativeSymbols.Contains(kv.Label);
     140
     141        foreach (ISymbolicExpressionTreeNode w in nodes2) {
     142          if (w.GetLength() != kv.Length || w.GetDepth() != kv.Depth || reverse.ContainsKey(w) || compactedGraph[w] != kv)
    107143            continue;
    108           w = t;
     144
     145          // map one whole subtree to the other
     146          foreach (var t in Subtrees(v, commutative).Zip(Subtrees(w, commutative), Tuple.Create)) {
     147            forward[t.Item1] = t.Item2;
     148            reverse[t.Item2] = t.Item1;
     149          }
     150
    109151          break;
    110152        }
    111         if (w == null) continue;
    112 
    113         // at this point we know that v and w are isomorphic, however, the mapping cannot be done directly
    114         // (as in the paper) because the trees are unordered (subtree order might differ). the solution is
    115         // to sort subtrees from under commutative labels (this will work because the subtrees are isomorphic!)
    116         // while iterating over the two subtrees
    117         var vv = IterateBreadthOrdered(v, comparer).ToList();
    118         var ww = IterateBreadthOrdered(w, comparer).ToList();
    119         int len = Math.Min(vv.Count, ww.Count);
    120         for (int j = 0; j < len; ++j) {
    121           var s = vv[j];
    122           var t = ww[j];
    123           Debug.Assert(!reverseMap.ContainsKey(t));
    124 
    125           forwardMap[s] = t;
    126           reverseMap[t] = s;
    127         }
    128       }
    129 
    130       return forwardMap;
     153      }
     154
     155      return forward;
    131156    }
    132157
     
    140165      var nodeMap = new Dictionary<ISymbolicExpressionTreeNode, GraphNode>(); // K
    141166      var labelMap = new Dictionary<string, GraphNode>(); // L
    142       var childrenCount = new Dictionary<ISymbolicExpressionTreeNode, int>(); // Children
    143167
    144168      var nodes = n1.IterateNodesPostfix().Concat(n2.IterateNodesPostfix()); // the disjoint union F
    145       var list = new List<GraphNode>();
    146       var queue = new Queue<ISymbolicExpressionTreeNode>();
    147 
    148       foreach (var n in nodes) {
    149         if (n.SubtreeCount == 0) {
    150           var label = GetLabel(n);
     169      var graph = new List<GraphNode>();
     170
     171      IEnumerable<GraphNode> Subtrees(GraphNode g, bool commutative) {
     172        var subtrees = g.SymbolicExpressionTreeNode.Subtrees.Select(x => nodeMap[x]);
     173        return commutative ? subtrees.OrderBy(x => x.Hash) : subtrees;
     174      }
     175
     176      foreach (var node in nodes) {
     177        var label = GetLabel(node);
     178
     179        if (node.SubtreeCount == 0) {
    151180          if (!labelMap.ContainsKey(label)) {
    152             var z = new GraphNode { SymbolicExpressionTreeNode = n, Label = label };
    153             labelMap[z.Label] = z;
    154           }
    155           nodeMap[n] = labelMap[label];
    156           queue.Enqueue(n);
     181            labelMap[label] = new GraphNode(node, label);
     182          }
     183          nodeMap[node] = labelMap[label];
    157184        } else {
    158           childrenCount[n] = n.SubtreeCount;
    159         }
    160       }
    161       while (queue.Any()) {
    162         var n = queue.Dequeue();
    163         if (n.SubtreeCount > 0) {
     185          var v = new GraphNode(node, label);
    164186          bool found = false;
    165           var label = n.Symbol.Name;
    166           var depth = n.GetDepth();
    167 
    168           bool sort = n.SubtreeCount > 1 && commutativeSymbols.Contains(label);
    169           var nSubtrees = n.Subtrees.Select(x => nodeMap[x]).ToList();
    170           if (sort) nSubtrees.Sort((a, b) => string.CompareOrdinal(a.Label, b.Label));
    171 
    172           for (int i = list.Count - 1; i >= 0; --i) {
    173             var w = list[i];
    174             if (!(n.SubtreeCount == w.SubtreeCount && label == w.Label && depth == w.Depth))
     187          var commutative = node.SubtreeCount > 1 && commutativeSymbols.Contains(label);
     188
     189          var vv = Subtrees(v, commutative);
     190
     191          foreach (var w in graph) {
     192            if (v.Depth != w.Depth || v.SubtreeCount != w.SubtreeCount || v.Length != w.Length || v.Label != w.Label) {
    175193              continue;
    176 
    177             // sort V and W when the symbol is commutative because we are dealing with unordered trees
    178             var m = w.SymbolicExpressionTreeNode;
    179             var mSubtrees = m.Subtrees.Select(x => nodeMap[x]).ToList();
    180             if (sort) mSubtrees.Sort((a, b) => string.CompareOrdinal(a.Label, b.Label));
    181 
    182             found = nSubtrees.SequenceEqual(mSubtrees);
     194            }
     195
     196            var ww = Subtrees(w, commutative);
     197            found = vv.SequenceEqual(ww);
     198
    183199            if (found) {
    184               nodeMap[n] = w;
     200              nodeMap[node] = w;
    185201              break;
    186202            }
    187203          }
    188 
    189204          if (!found) {
    190             var w = new GraphNode { SymbolicExpressionTreeNode = n, Label = label, Depth = depth };
    191             list.Add(w);
    192             nodeMap[n] = w;
     205            nodeMap[node] = v;
     206            graph.Add(v);
    193207          }
    194208        }
    195 
    196         if (n == n1 || n == n2)
    197           continue;
    198 
    199         var p = n.Parent;
    200         if (p == null)
    201           continue;
    202 
    203         childrenCount[p]--;
    204 
    205         if (childrenCount[p] == 0)
    206           queue.Enqueue(p);
    207       }
    208 
     209      }
    209210      return nodeMap;
    210     }
    211 
    212     private IEnumerable<ISymbolicExpressionTreeNode> IterateBreadthOrdered(ISymbolicExpressionTreeNode node, ISymbolicExpressionTreeNodeComparer comparer) {
    213       var list = new List<ISymbolicExpressionTreeNode> { node };
    214       int i = 0;
    215       while (i < list.Count) {
    216         var n = list[i];
    217         if (n.SubtreeCount > 0) {
    218           var subtrees = commutativeSymbols.Contains(node.Symbol.Name) ? n.Subtrees.OrderBy(x => x, comparer) : n.Subtrees;
    219           list.AddRange(subtrees);
    220         }
    221         i++;
    222       }
    223       return list;
    224211    }
    225212
     
    228215        return node.Symbol.Name;
    229216
    230       var constant = node as ConstantTreeNode;
    231       if (constant != null)
    232         return MatchConstantValues ? constant.Value.ToString(CultureInfo.InvariantCulture) : node.Symbol.Name;
    233 
    234       var variable = node as VariableTreeNode;
    235       if (variable != null)
     217      if (node is ConstantTreeNode constant)
     218        return MatchConstantValues ? constant.Value.ToString(CultureInfo.InvariantCulture) : constant.Symbol.Name;
     219
     220      if (node is VariableTreeNode variable)
    236221        return MatchVariableWeights ? variable.Weight + variable.VariableName : variable.VariableName;
    237222
     
    240225
    241226    private class GraphNode {
    242       public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode;
    243       public string Label;
    244       public int Depth;
     227      private GraphNode() { }
     228
     229      public GraphNode(ISymbolicExpressionTreeNode node, string label) {
     230        SymbolicExpressionTreeNode = node;
     231        Label = label;
     232        Hash = GetHashCode();
     233        Depth = node.GetDepth();
     234        Length = node.GetLength();
     235      }
     236
     237      public int Hash { get; }
     238      public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode { get; }
     239      public string Label { get; }
     240      public int Depth { get; }
    245241      public int SubtreeCount { get { return SymbolicExpressionTreeNode.SubtreeCount; } }
     242      public int Length { get; }
    246243    }
    247244  }
Note: See TracChangeset for help on using the changeset viewer.