Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
05/02/13 13:18:57 (11 years ago)
Author:
bburlacu
Message:

#1772: Refactoring of directed graph components, added code for correctly serializing vertices and edges. Added specific building blocks analyzers and new population diversity analyzer which correctly integrates with the parallel engine.

Location:
branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking/3.4/Analyzers
Files:
3 added
2 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking/3.4/Analyzers/SymbolicExpressionTreeFrequentPatternsAnalyzer.cs

    r9238 r9419  
    204204        var grammar = trees[0].Root.Grammar;
    205205
    206         // bring trees to a canonical form to eliminate permuted fragments
    207         var canonicalSorter = new SymbolicExpressionTreeCanonicalSorter();
    208         foreach (var t in trees)
    209           canonicalSorter.SortSubtrees(t);
    210 
    211206        var graph = Results["SymbolGraph"].Value as SymbolGraph;
    212207
     
    217212        // subtree-sort fragments to bring them to a canonical form
    218213        // var canonicalSorter = new SymbolicExpressionTreeCanonicalSorter();
    219         foreach (var fragment in fragments)
    220           canonicalSorter.SortSubtrees(fragment.Root);
    221214
    222215        if (!Results.ContainsKey(CommonFragmentsParameterName)) {
     
    342335        int minCount = grammar.GetMinimumSubtreeCount(node.Symbol);
    343336        var arity = random.Next(enforceGrammarArity ? minCount : 1, maxCount + 1);
    344         var possibleChildConnections = new List<Arc>();
     337        var possibleChildConnections = new List<SymbolArc>();
    345338
    346339        if (depthLimit <= 2 || lengthLimit <= maxCount) { // if we are near the depth limit then we want to add leafs on the next level
  • branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking/3.4/Analyzers/SymbolicExpressionTreePopulationDiversityAnalyzer.cs

    r9296 r9419  
    4444  public sealed class SymbolicExpressionTreePopulationDiversityAnalyzer : SingleSuccessorOperator, IAnalyzer {
    4545    #region Parameter names
     46    private const string MaximumSymbolicExpressionTreeDepthParameterName = "MaximumSymbolicExpressionTreeDepth";
    4647    private const string SymbolicExpressionTreeParameterName = "SymbolicExpressionTree";
    4748    private const string UpdateIntervalParameterName = "UpdateInterval";
     
    5657    private const string SortSubtreesParameterName = "SortSubtrees";
    5758    private const string SimilarityValuesParmeterName = "Similarity";
    58     // population graph
    59     private const string PopulationGraphParameterName = "PopulationGraph";
    6059    // clone map
    6160    private const string GlobalCloneMapParameterName = "GlobalCloneMap";
     
    6463
    6564    #region Parameters
     65    public IValueLookupParameter<IntValue> MaximumSymbolicExpressionTreeDepthParameter {
     66      get { return (IValueLookupParameter<IntValue>)Parameters[MaximumSymbolicExpressionTreeDepthParameterName]; }
     67    }
    6668
    6769    public ValueParameter<IntValue> UpdateIntervalParameter {
     
    116118
    117119    #region Parameter properties
     120    public IntValue MaximumSymbolicExpressionTreeDepth {
     121      get { return MaximumSymbolicExpressionTreeDepthParameter.ActualValue; }
     122    }
    118123
    119124    public IntValue UpdateInterval {
     
    164169      Parameters.Add(new ValueLookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should be stored."));
    165170      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
    166       Parameters.Add(new ValueParameter<BoolValue>(MatchVariablesParameterName, "Specify if the symbolic expression tree comparer should match variable names."));
    167       Parameters.Add(new ValueParameter<BoolValue>(MatchVariableWeightsParameterName, "Specify if the symbolic expression tree comparer should match variable weights."));
    168       Parameters.Add(new ValueParameter<BoolValue>(MatchConstantValuesParameterName, "Specify if the symbolic expression tree comparer should match constant values."));
     171      Parameters.Add(new ValueParameter<BoolValue>(MatchVariablesParameterName, "Specify if the symbolic expression tree comparer should match variable names.", new BoolValue(true)));
     172      Parameters.Add(new ValueParameter<BoolValue>(MatchVariableWeightsParameterName, "Specify if the symbolic expression tree comparer should match variable weights.", new BoolValue(true)));
     173      Parameters.Add(new ValueParameter<BoolValue>(MatchConstantValuesParameterName, "Specify if the symbolic expression tree comparer should match constant values.", new BoolValue(true)));
    169174      Parameters.Add(new ValueParameter<BoolValue>(SortSubtreesParameterName, "Specifies whether the subtrees of a tree should be sorted before comparison."));
    170175      Parameters.Add(new LookupParameter<CloneMapType>(GlobalCloneMapParameterName, "A global map keeping track of trees and their clones (made during selection)."));
    171176      Parameters.Add(new ValueParameter<BoolValue>(StoreHistoryParameterName, "True if the tree lengths history of the population should be stored.", new BoolValue(false)));
    172177      Parameters.Add(new LookupParameter<DoubleValue>(SimilarityValuesParmeterName, ""));
     178      Parameters.Add(new ValueLookupParameter<IntValue>(MaximumSymbolicExpressionTreeDepthParameterName, "The maximal depth of the symbolic expression tree (a tree with one node has depth = 0)."));
    173179      UpdateCounterParameter.Hidden = true;
    174180      UpdateIntervalParameter.Hidden = true;
     
    177183    [StorableHook(HookType.AfterDeserialization)]
    178184    private void AfterDeserialization() {
     185      if (!Parameters.ContainsKey(MaximumSymbolicExpressionTreeDepthParameterName)) {
     186        Parameters.Add(new ValueLookupParameter<IntValue>(MaximumSymbolicExpressionTreeDepthParameterName, "The maximal depth of the symbolic expression tree (a tree with one node has depth = 0)."));
     187      }
    179188    }
    180189
    181190    #region IStatefulItem members
    182191    public override void InitializeState() {
     192      UpdateCounter.Value = 0;
    183193      base.InitializeState();
    184       UpdateCounter.Value = 0;
    185     }
    186 
    187     public override void ClearState() {
    188       base.ClearState();
    189       UpdateCounter.Value = 0;
    190194    }
    191195    #endregion
     
    199203        UpdateCounter.Value++;
    200204        if (UpdateCounter.Value != UpdateInterval.Value) return base.Apply();
    201 
    202205        UpdateCounter.Value = 0;
    203206        var trees = SymbolicExpressionTreeParameter.ActualValue.ToList();
     
    208211
    209212        SimilarityParameter.ActualValue = new DoubleValue();
     213        // needed only with the old (and inefficient) geneticitem-based similarity measure
     214        //        var geneticItems = trees.ToDictionary(tree => tree, tree => tree.GetGeneticItems(1, MaximumSymbolicExpressionTreeDepth.Value - 2).ToArray());
    210215
    211216        var comp = new SymbolicExpressionTreeNodeSimilarityComparer {
     
    217222        var operations = new OperationCollection { Parallel = true };
    218223        foreach (var tree in trees) {
    219           var op = new SymbolicDataAnalysisExpressionTreeSimilarityCalculator { CurrentSymbolicExpressionTree = tree, SimilarityComparer = comp };
     224          var op = new SymbolicDataAnalysisExpressionTreeSimilarityCalculator { CurrentSymbolicExpressionTree = tree, SimilarityComparer = comp, MaximumTreeDepth = MaximumSymbolicExpressionTreeDepth.Value };
    220225          var operation = ExecutionContext.CreateChildOperation(op, ExecutionContext.Scope);
    221226          operations.Add(operation);
     
    256261      relativeSelectionCountsTable.Rows["SelectedIndividuals"].Values.Add(relativeSelectionCount);
    257262
    258       // build a selection frequencies histogram
    259       var graph = (SymbolicExpressionTreeGenealogyGraph)results[PopulationGraphParameterName].Value;
    260       // get graph nodes corresponding to individuals of the previous generation
    261       var prevGen = graph.Nodes.Where(node => node.Rank.IsAlmost(Generations.Value - 1)).OrderByDescending(n => n.Quality).ToList();
    262       var frequencies = new double[SymbolicExpressionTreeParameter.ActualValue.Length];
    263       for (int i = 0; i != prevGen.Count; ++i) {
    264         int selFreq = GlobalCloneMap.Values.Count(t => t == prevGen[i].SymbolicExpressionTree);
    265         frequencies[i] = selFreq;
    266       }
    267       DataTable selectionFrequenciesTable;
    268       if (!results.ContainsKey("SelectionFrequencies")) {
    269         selectionFrequenciesTable = new DataTable("Selection Frequencies") { VisualProperties = { YAxisTitle = "Selection Count" } };
    270         results.Add(new Result("SelectionFrequencies", selectionFrequenciesTable));
    271       }
    272       selectionFrequenciesTable = (DataTable)results["SelectionFrequencies"].Value;
    273       DataRow histoRow;
    274       if (!selectionFrequenciesTable.Rows.ContainsKey("SelectionFrequencies")) {
    275         histoRow = new DataRow("SelectionFrequencies") { VisualProperties = { StartIndexZero = true } };
    276         selectionFrequenciesTable.Rows.Add(histoRow);
    277       }
    278       histoRow = selectionFrequenciesTable.Rows["SelectionFrequencies"];
    279       histoRow.Values.Replace(frequencies);
    280 
    281       bool storeHistory = StoreHistory.Value;
    282       if (storeHistory) {
    283         DataTableHistory selectionFrequenciesHistory;
    284         if (!results.ContainsKey("SelectionFrequenciesHistory")) {
    285           selectionFrequenciesHistory = new DataTableHistory();
    286           results.Add(new Result("SelectionFrequenciesHistory", selectionFrequenciesHistory));
    287         }
    288         selectionFrequenciesHistory = (DataTableHistory)results["SelectionFrequenciesHistory"].Value;
    289         selectionFrequenciesHistory.Add((DataTable)selectionFrequenciesTable.Clone());
    290       }
    291263      return base.Apply();
    292264    }
  • branches/HeuristicLab.EvolutionaryTracking/HeuristicLab.EvolutionaryTracking/3.4/Analyzers/SymbolicExpressionTreeShapeAnalyzer.cs

    r9082 r9419  
    2020#endregion
    2121
    22 using System.Collections.Generic;
    2322using System.Linq;
    2423using HeuristicLab.Common;
     
    3029using HeuristicLab.Parameters;
    3130using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    32 using HeuristicLab.Problems.DataAnalysis;
    33 using HeuristicLab.Problems.DataAnalysis.Symbolic;
    34 // type definitions for convenience
    35 using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
    36 using CloneMapType = HeuristicLab.Core.ItemDictionary<HeuristicLab.Core.IItem, HeuristicLab.Core.IItem>;
    37 using TraceMapType = HeuristicLab.Core.ItemDictionary<HeuristicLab.Core.IItem, HeuristicLab.Core.IItemList<HeuristicLab.Core.IItem>>;
    3831
    3932namespace HeuristicLab.EvolutionaryTracking {
     
    4437  [Item("SymbolicExpressionTreeFragmentsAnalyzer", "An operator that provides statistics about crossover fragments")]
    4538  [StorableClass]
    46   public abstract class SymbolicExpressionTreeFragmentsAnalyzer : SingleSuccessorOperator, IAnalyzer {
     39  public sealed class SymbolicExpressionTreeShapeAnalyzer : SingleSuccessorOperator, IAnalyzer {
    4740    #region Parameter names
    48     protected const string UpdateIntervalParameterName = "UpdateInterval";
    49     protected const string UpdateCounterParameterName = "UpdateCounter";
    50     protected const string ResultsParameterName = "Results";
    51     protected const string SecondaryTraceMapParameterName = "SecondaryTraceMap";
    52     protected const string SecondaryFragmentMapParameterName = "SecondaryFragmentMap";
    53     protected const string SecondaryCloneMapParameterName = "SecondaryCloneMap";
    54     protected const string GlobalTraceMapParameterName = "GlobalTraceMap";
    55     protected const string GlobalTraceMapParameterDescription = "Global map of trees and their parents.";
    56     protected const string GlobalCloneMapParameterName = "GlobalCloneMap";
    57     protected const string GlobalCloneMapParameterDescription = "Global map of trees and their clones";
    58     protected const string GlobalFragmentMapParameterName = "GlobalFragmentMap";
    59     protected const string GlobalFragmentMapParameterDescription = "Global map of trees and their respective fragments.";
    60     protected const string GenerationsParameterName = "Generations";
    61     protected const string SymbolicExpressionInterpreterParameterName = "SymbolicExpressionTreeInterpreter";
    62     protected const string SymbolicRegressionProblemDataParameterName = "ProblemData";
     41    private const string UpdateIntervalParameterName = "UpdateInterval";
     42    private const string UpdateCounterParameterName = "UpdateCounter";
     43    private const string ResultsParameterName = "Results";
     44    private const string GenerationsParameterName = "Generations";
    6345    #endregion
    64 
    65     // impact values calculator
    66     private readonly SymbolicRegressionSolutionImpactValuesCalculator calculator = new SymbolicRegressionSolutionImpactValuesCalculator();
    6746
    6847    #region Parameter properties
     
    7857    public LookupParameter<IntValue> GenerationsParameter {
    7958      get { return (LookupParameter<IntValue>)Parameters[GenerationsParameterName]; }
    80     }
    81     // tracking structures
    82     public LookupParameter<TraceMapType> GlobalTraceMapParameter {
    83       get { return (LookupParameter<TraceMapType>)Parameters[GlobalTraceMapParameterName]; }
    84     }
    85     public LookupParameter<CloneMapType> GlobalCloneMapParameter {
    86       get { return (LookupParameter<CloneMapType>)Parameters[GlobalCloneMapParameterName]; }
    87     }
    88     public LookupParameter<CloneMapType> GlobalFragmentMapParameter {
    89       get { return (LookupParameter<CloneMapType>)Parameters[GlobalFragmentMapParameterName]; }
    90     }
    91     // auxiliary structures for tracking fragments and individuals from the previous generation
    92     // (this is needed because tracking is done in connection to the current generation, i.e., for
    93     // counting "successful" offspring and fragments
    94     public LookupParameter<TraceMapType> SecondaryTraceMapParameter {
    95       get { return (LookupParameter<TraceMapType>)Parameters[SecondaryTraceMapParameterName]; }
    96     }
    97     public LookupParameter<CloneMapType> SecondaryFragmentMapParameter {
    98       get { return (LookupParameter<CloneMapType>)Parameters[SecondaryFragmentMapParameterName]; }
    99     }
    100     public LookupParameter<CloneMapType> SecondaryCloneMapParameter {
    101       get { return (LookupParameter<CloneMapType>)Parameters[SecondaryCloneMapParameterName]; }
    102     }
    103     // problem data, interpreter and evaluator
    104     public LookupParameter<SymbolicDataAnalysisExpressionTreeInterpreter> SymbolicExpressionInterpreterParameter {
    105       get { return (LookupParameter<SymbolicDataAnalysisExpressionTreeInterpreter>)Parameters[SymbolicExpressionInterpreterParameterName]; }
    106     }
    107     public LookupParameter<RegressionProblemData> SymbolicRegressionProblemDataParameter {
    108       get { return (LookupParameter<RegressionProblemData>)Parameters[SymbolicRegressionProblemDataParameterName]; }
    10959    }
    11060    #endregion
     
    12373      get { return ResultsParameter.ActualValue; }
    12474    }
    125     public CloneMapType GlobalCloneMap {
    126       get { return GlobalCloneMapParameter.ActualValue; }
    127     }
    128     public TraceMapType GlobalTraceMap {
    129       get { return GlobalTraceMapParameter.ActualValue; }
    130     }
    131     public TraceMapType SecondaryTraceMap {
    132       get { return SecondaryTraceMapParameter.ActualValue; }
    133       set { SecondaryTraceMapParameter.ActualValue = value; }
    134     }
    135     public CloneMapType SecondaryFragmentMap {
    136       get { return SecondaryFragmentMapParameter.ActualValue; }
    137       set { SecondaryFragmentMapParameter.ActualValue = value; }
    138     }
    139     public CloneMapType SecondaryCloneMap {
    140       get { return SecondaryCloneMapParameter.ActualValue; }
    141       set { SecondaryCloneMapParameter.ActualValue = value; }
    142     }
    143     public CloneMapType GlobalFragmentMap {
    144       get { return GlobalFragmentMapParameter.ActualValue; }
    145     }
    14675    public IntValue Generations {
    14776      get { return GenerationsParameter.ActualValue; }
    148     }
    149     public SymbolicDataAnalysisExpressionTreeInterpreter SymbolicExpressionInterpreter {
    150       get { return SymbolicExpressionInterpreterParameter.ActualValue; }
    151     }
    152     public RegressionProblemData SymbolicRegressionProblemData {
    153       get { return SymbolicRegressionProblemDataParameter.ActualValue; }
    15477    }
    15578    #endregion
    15679
    15780    [StorableConstructor]
    158     protected SymbolicExpressionTreeFragmentsAnalyzer(bool deserializing) : base(deserializing) { }
     81    private SymbolicExpressionTreeShapeAnalyzer(bool deserializing) : base(deserializing) { }
    15982
    160     protected SymbolicExpressionTreeFragmentsAnalyzer(SymbolicExpressionTreeFragmentsAnalyzer original, Cloner cloner) : base(original, cloner) { }
     83    private SymbolicExpressionTreeShapeAnalyzer(SymbolicExpressionTreeShapeAnalyzer original, Cloner cloner) : base(original, cloner) { }
    16184
    162     protected SymbolicExpressionTreeFragmentsAnalyzer()
     85    private SymbolicExpressionTreeShapeAnalyzer()
    16386      : base() {
    16487      #region Add parameters
     
    16689      Parameters.Add(new ValueParameter<IntValue>(UpdateIntervalParameterName, "The interval in which the tree length analysis should be applied.", new IntValue(1)));
    16790      Parameters.Add(new ValueParameter<IntValue>(UpdateCounterParameterName, "The value which counts how many times the operator was called since the last update", new IntValue(0)));
    168       // tracking
    169       Parameters.Add(new LookupParameter<TraceMapType>(GlobalTraceMapParameterName, GlobalTraceMapParameterDescription));
    170       Parameters.Add(new LookupParameter<CloneMapType>(GlobalCloneMapParameterName, GlobalCloneMapParameterDescription));
    171       Parameters.Add(new LookupParameter<CloneMapType>(GlobalFragmentMapParameterName, GlobalFragmentMapParameterDescription));
    172       // secondary tracking
    173       Parameters.Add(new LookupParameter<TraceMapType>(SecondaryTraceMapParameterName, GlobalTraceMapParameterDescription));
    174       Parameters.Add(new LookupParameter<CloneMapType>(SecondaryCloneMapParameterName, GlobalCloneMapParameterDescription));
    175       Parameters.Add(new LookupParameter<CloneMapType>(SecondaryFragmentMapParameterName, GlobalFragmentMapParameterDescription));
    176       // impact calculation
    177       Parameters.Add(new LookupParameter<SymbolicDataAnalysisExpressionTreeInterpreter>(SymbolicExpressionInterpreterParameterName, "Interpreter for symbolic expression trees"));
    178       Parameters.Add(new LookupParameter<RegressionProblemData>(SymbolicRegressionProblemDataParameterName, "The symbolic data analysis problem."));
    179       // fragment statistics parameters
    18091      Parameters.Add(new ValueLookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should be stored."));
    18192      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
     
    211122    #endregion
    212123
    213     /* A small description of the way this analyzer works
    214      *
    215      * We keep 3 maps in the global scope: the GlobalTraceMap, the GlobalFragmentMap and the GlobalCloneMap that are updated on each step: selection, crossover, mutation
    216      * These maps provide information about the children, parents and transferred fragments as follows:
    217      *
    218      * 1) GlobalCloneMap
    219      *    This data structure provides the basis for tracking. In the selection step, every selected individual gets cloned and transferred into the recombination pool.
    220      *    The GlobalCloneMap keeps track of clones by mapping them to the original individuals. This is an essential step for building the genealogy graph. Using this
    221      *    structure we can find out how many times each individual was selected.
    222      *    The GlobalCloneMap consists of Key-Value pairs Clone->Original
    223      *
    224      * 2) GlobalTraceMap
    225      *    Keeps information in the form of key-value pairs Child->{Parents}, where {Parents} is a set consisting of
    226      *      - one parent individual (in the case of mutation), by language abuse we say that the individual that mutation acted on is the parent,
    227      *        and the resulting individual is the child
    228      *      - two parent individuals (in the case of crossover), named Parent0 and Parent1. Parent0 is the individual that crossover acts on by replacing
    229      *        one of its subtrees with a compatible subtree, randomly selected from Parent1
    230      *
    231      *    CROSSOVER
    232      *        Parent0     Parent1                                                                    {Parents}
    233      *           \           /                                                                           ^
    234      *            \       fragment (inserted from Parent1 into Parent0 to create the Child)              ^    [Mapping provided by the GlobalTraceMap]
    235      *             \       /                                                                             ^
    236      *              \     /                                                                              ^
    237      *               Child                                                                             Child
    238      *               
    239      *    MUTATION
    240      *        Parent0
    241      *           |
    242      *           |    [mutation acts on a random node/subtree in the 'parent' individual
    243      *           |
    244      *         Child
    245      *         
    246      *    Since crossover and mutation act on individuals in the recombination pool (which in fact are clones of individuals from the previous generation), the GlobalTraceMap
    247      *    is populated with values given by the mappings in the GlobalCloneMap, so that the original parent for each child is known.
    248      *   
    249      *  3) GlobalFragmentMap
    250      *     Keeps information in the form of Key-Value pairs about an individual and its respective fragment
    251      *     (ie., the subtree received via crossover or created/altered by mutation)
    252      * */
     124    public override IOperation Apply() {
    253125
    254     public override IOperation Apply() {
    255       // save the current generation so it can be compared to the following one, next time the analyzer is applied
    256       SecondaryTraceMap = SecondaryTraceMap ?? new TraceMapType();
    257       SecondaryCloneMap = SecondaryCloneMap ?? new CloneMapType();
    258       SecondaryFragmentMap = SecondaryFragmentMap ?? new CloneMapType();
    259 
    260       SecondaryTraceMap.Clear();
    261       if (GlobalTraceMap != null)
    262         foreach (var m in GlobalTraceMap)
    263           SecondaryTraceMap.Add(m.Key, m.Value);
    264 
    265       SecondaryCloneMap.Clear();
    266       if (GlobalCloneMap != null)
    267         foreach (var m in GlobalCloneMap)
    268           SecondaryCloneMap.Add(m.Key, m.Value);
    269 
    270       SecondaryFragmentMap.Clear();
    271       if (GlobalFragmentMap != null)
    272         foreach (var m in GlobalFragmentMap)
    273           SecondaryFragmentMap.Add(m.Key, m.Value);
    274126      return base.Apply();
    275     }
    276 
    277     protected virtual void InitializeParameters() {
    278       #region Init parameters
    279 
    280       #endregion
    281127    }
    282128
     
    285131    }
    286132
     133    private static int PathLength(ISymbolicExpressionTree tree) {
     134      return PathLength(tree.Root);
     135    }
     136
    287137    private static int VisitationLength(ISymbolicExpressionTreeNode node) {
    288138      return node.IterateNodesBreadth().Sum(n => n.GetLength());
    289139    }
    290140
    291     #region Similarity computations
    292     /// <summary>
    293     /// Provide a measure of how similar the fragments that get passed by crossover from one generation to the next are.
    294     /// </summary>
    295     /// <param name="fragments">The symbolic expression tree fragments</param>
    296     /// <param name="mode">The similarity mode (0 - exact, 1 - high, 2 - relaxed)</param>
    297     /// <returns>The average number of similar fragments</returns>
    298     private static double CalculateSimilarity(IList<IFragment> fragments, SymbolicExpressionTreeNodeSimilarityComparer comparer) {
    299       var visited = new bool[fragments.Count];
    300       int groups = 0;
    301       for (int i = 0; i != fragments.Count - 1; ++i) {
    302         if (visited[i]) continue;
    303         for (int j = i + 1; j != fragments.Count; ++j) {
    304           if (visited[j]) continue;
    305           if (fragments[i].Root.IsSimilarTo(fragments[j].Root, comparer))
    306             visited[j] = true;
    307         }
    308         ++groups;
    309       }
    310       return (double)fragments.Count / groups;
     141    private static int PathLength(ISymbolicExpressionTreeNode node) {
     142      return node.IterateNodesBreadth().Sum(n => node.GetBranchLevel(n)) + 1;
    311143    }
    312     #endregion
     144
     145    public override IDeepCloneable Clone(Cloner cloner) {
     146      return new SymbolicExpressionTreeShapeAnalyzer(this, cloner);
     147    }
    313148  } //SymbolicExpressionTreeFragmentsAnalyzer
    314149}
Note: See TracChangeset for help on using the changeset viewer.