Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2886_SymRegGrammarEnumeration/HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration/GrammarEnumeration/GrammarEnumerationAlgorithm.cs @ 15975

Last change on this file since 15975 was 15975, checked in by bburlacu, 6 years ago

#2886: address additional serialization issues, make Production implement IList<T> instead of deriving from List<T>

File size: 25.8 KB
RevLine 
[15765]1using System;
2using System.Collections.Generic;
[15712]3using System.Linq;
4using System.Threading;
5using HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration.GrammarEnumeration;
[15957]6using HeuristicLab.Collections;
[15712]7using HeuristicLab.Common;
8using HeuristicLab.Core;
9using HeuristicLab.Data;
10using HeuristicLab.Optimization;
[15722]11using HeuristicLab.Parameters;
[15712]12using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
13using HeuristicLab.Problems.DataAnalysis;
[15974]14using HeuristicLab.Problems.DataAnalysis.Symbolic;
15using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
[15712]16
17namespace HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration {
18  [Item("Grammar Enumeration Symbolic Regression", "Iterates all possible model structures for a fixed grammar.")]
19  [StorableClass]
20  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 250)]
21  public class GrammarEnumerationAlgorithm : FixedDataAnalysisAlgorithm<IRegressionProblem> {
[15746]22    #region properties and result names
[15950]23    private readonly string VariableImportanceWeightName = "Variable Importance Weight";
[15803]24    private readonly string SearchStructureSizeName = "Search Structure Size";
25    private readonly string GeneratedPhrasesName = "Generated/Archived Phrases";
[15746]26    private readonly string GeneratedSentencesName = "Generated Sentences";
27    private readonly string DistinctSentencesName = "Distinct Sentences";
28    private readonly string PhraseExpansionsName = "Phrase Expansions";
[15860]29    private readonly string AverageSentenceComplexityName = "Avg. Sentence Complexity among Distinct";
[15821]30    private readonly string OverwrittenSentencesName = "Sentences overwritten";
31    private readonly string AnalyzersParameterName = "Analyzers";
[15824]32    private readonly string ExpansionsPerSecondName = "Expansions per second";
[15712]33
[15861]34    private readonly string OptimizeConstantsParameterName = "Optimize Constants";
[15910]35    private readonly string ErrorWeightParameterName = "Error Weight";
[15746]36    private readonly string SearchDataStructureParameterName = "Search Data Structure";
[15860]37    private readonly string MaxComplexityParameterName = "Max. Complexity";
[15722]38    private readonly string GuiUpdateIntervalParameterName = "GUI Update Interval";
[15930]39    private readonly string GrammarSymbolsParameterName = "Grammar Symbols";
[15974]40    private readonly string SearchCacheSizeParameterName = "Search Cache Size";
41    private readonly string SearchDataStructureSizeParameterName = "Search Data Structure Size";
[15765]42
[15974]43    // result names
44    public static readonly string BestTrainingModelResultName = "Best model (Training)";
45    public static readonly string BestTrainingSolutionResultName = "Best solution (Training)";
46    public static readonly string BestComplexityResultName = "Best solution complexity";
47
[15960]48    public override bool SupportsPause { get { return true; } }
[15712]49
[15974]50    protected IFixedValueParameter<DoubleValue> VariableImportanceWeightParameter {
51      get { return (IFixedValueParameter<DoubleValue>)Parameters[VariableImportanceWeightName]; }
[15950]52    }
53
[15975]54    public double VariableImportanceWeight {
[15950]55      get { return VariableImportanceWeightParameter.Value.Value; }
[15975]56      set { VariableImportanceWeightParameter.Value.Value = value; }
[15950]57    }
58
[15974]59    protected IFixedValueParameter<BoolValue> OptimizeConstantsParameter {
60      get { return (IFixedValueParameter<BoolValue>)Parameters[OptimizeConstantsParameterName]; }
[15861]61    }
62
63    public bool OptimizeConstants {
64      get { return OptimizeConstantsParameter.Value.Value; }
65      set { OptimizeConstantsParameter.Value.Value = value; }
66    }
67
[15974]68    protected IFixedValueParameter<IntValue> MaxComplexityParameter {
69      get { return (IFixedValueParameter<IntValue>)Parameters[MaxComplexityParameterName]; }
[15712]70    }
[15974]71
[15860]72    public int MaxComplexity {
73      get { return MaxComplexityParameter.Value.Value; }
74      set { MaxComplexityParameter.Value.Value = value; }
[15722]75    }
[15712]76
[15974]77    protected IFixedValueParameter<DoubleValue> ErrorWeightParameter {
78      get { return (IFixedValueParameter<DoubleValue>)Parameters[ErrorWeightParameterName]; }
[15910]79    }
[15974]80
[15910]81    public double ErrorWeight {
82      get { return ErrorWeightParameter.Value.Value; }
83      set { ErrorWeightParameter.Value.Value = value; }
84    }
85
[15974]86    protected IFixedValueParameter<IntValue> GuiUpdateIntervalParameter {
87      get { return (IFixedValueParameter<IntValue>)Parameters[GuiUpdateIntervalParameterName]; }
[15722]88    }
[15974]89
[15722]90    public int GuiUpdateInterval {
91      get { return GuiUpdateIntervalParameter.Value.Value; }
[15723]92      set { GuiUpdateIntervalParameter.Value.Value = value; }
[15722]93    }
[15712]94
[15974]95    protected IFixedValueParameter<EnumValue<StorageType>> SearchDataStructureParameter {
96      get { return (IFixedValueParameter<EnumValue<StorageType>>)Parameters[SearchDataStructureParameterName]; }
[15723]97    }
[15974]98
99    public IFixedValueParameter<IntValue> SearchDataStructureSizeParameter {
100      get { return (IFixedValueParameter<IntValue>)Parameters[SearchDataStructureSizeParameterName]; }
101    }
102
103    public int SearchDataStructureSize {
104      get { return SearchDataStructureSizeParameter.Value.Value; }
105    }
106
107    public IFixedValueParameter<IntValue> SearchCacheSizeParameter {
108      get { return (IFixedValueParameter<IntValue>)Parameters[SearchCacheSizeParameterName]; }
109    }
110
111    public int SearchCacheSize {
112      get { return SearchCacheSizeParameter.Value.Value; }
113    }
114
[15746]115    public StorageType SearchDataStructure {
116      get { return SearchDataStructureParameter.Value.Value; }
117      set { SearchDataStructureParameter.Value.Value = value; }
[15723]118    }
119
[15821]120    public IFixedValueParameter<ReadOnlyCheckedItemCollection<IGrammarEnumerationAnalyzer>> AnalyzersParameter {
121      get { return (IFixedValueParameter<ReadOnlyCheckedItemCollection<IGrammarEnumerationAnalyzer>>)Parameters[AnalyzersParameterName]; }
122    }
123
124    public ICheckedItemCollection<IGrammarEnumerationAnalyzer> Analyzers {
125      get { return AnalyzersParameter.Value; }
126    }
127
[15930]128    public IFixedValueParameter<ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>>> GrammarSymbolsParameter {
129      get { return (IFixedValueParameter<ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>>>)Parameters[GrammarSymbolsParameterName]; }
130    }
131
132    public ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>> GrammarSymbols {
133      get { return GrammarSymbolsParameter.Value; }
134    }
135
[15975]136    [Storable]
[15824]137    public SymbolString BestTrainingSentence { get; set; }     // Currently set in RSquaredEvaluator: quite hacky, but makes testing much easier for now...
[15722]138    #endregion
[15712]139
[15960]140    [Storable]
[15860]141    public Dictionary<int, int> DistinctSentencesComplexity { get; private set; }  // Semantically distinct sentences and their length in a run.
[15960]142
143    [Storable]
[15812]144    public HashSet<int> ArchivedPhrases { get; private set; }
[15960]145
146    [Storable]
[15821]147    internal SearchDataStore OpenPhrases { get; private set; }           // Stack/Queue/etc. for fetching the next node in the search tree. 
[15812]148
[15821]149    #region execution stats
[15974]150    [Storable]
[15821]151    public int AllGeneratedSentencesCount { get; private set; }
[15746]152
[15974]153    [Storable]
[15821]154    public int OverwrittenSentencesCount { get; private set; } // It is not guaranteed that shorter solutions are found first.
155                                                               // When longer solutions are overwritten with shorter ones,
156                                                               // this counter is increased.
[15974]157    [Storable]
[15821]158    public int PhraseExpansionCount { get; private set; }      // Number, how many times a nonterminal symbol is replaced with a production rule.
159    #endregion
160
[15975]161    [Storable]
[15800]162    public Grammar Grammar { get; private set; }
[15712]163
[15722]164    #region ctors
165    public override IDeepCloneable Clone(Cloner cloner) {
166      return new GrammarEnumerationAlgorithm(this, cloner);
167    }
[15712]168
[15975]169    [StorableConstructor]
170    protected GrammarEnumerationAlgorithm(bool deserializing) : base(deserializing) { }
171
[15722]172    public GrammarEnumerationAlgorithm() {
[15974]173      Parameters.Add(new FixedValueParameter<DoubleValue>(VariableImportanceWeightName, "Variable Weight.", new DoubleValue(1.0)));
174      Parameters.Add(new FixedValueParameter<BoolValue>(OptimizeConstantsParameterName, "Run constant optimization in sentence evaluation.", new BoolValue(false)));
175      Parameters.Add(new FixedValueParameter<DoubleValue>(ErrorWeightParameterName, "Defines, how much weight is put on a phrase's r² value when priorizing phrases during search.", new DoubleValue(0.8)));
176      Parameters.Add(new FixedValueParameter<IntValue>(MaxComplexityParameterName, "The maximum number of variable symbols in a sentence.", new IntValue(12)));
177      Parameters.Add(new FixedValueParameter<IntValue>(GuiUpdateIntervalParameterName, "Number of generated sentences, until GUI is refreshed.", new IntValue(5000)));
178      Parameters.Add(new FixedValueParameter<IntValue>(SearchCacheSizeParameterName, "The size of the search node cache.", new IntValue((int)1e5)));
179      Parameters.Add(new FixedValueParameter<IntValue>(SearchDataStructureSizeParameterName, "The size of the search data structure.", new IntValue((int)1e5)));
180      Parameters.Add(new FixedValueParameter<EnumValue<StorageType>>(SearchDataStructureParameterName, new EnumValue<StorageType>(StorageType.PriorityQueue)));
[15821]181
[15974]182      SearchDataStructureParameter.Value.ValueChanged += (o, e) => Prepare();
183      SearchDataStructureSizeParameter.Value.ValueChanged += (o, e) => Prepare();
184      SearchCacheSizeParameter.Value.ValueChanged += (o, e) => Prepare();
185
[15821]186      var availableAnalyzers = new IGrammarEnumerationAnalyzer[] {
187        new SearchGraphVisualizer(),
[15824]188        new SentenceLogger(),
189        new RSquaredEvaluator()
[15821]190      };
[15974]191
[15821]192      Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemCollection<IGrammarEnumerationAnalyzer>>(
193        AnalyzersParameterName,
194        new CheckedItemCollection<IGrammarEnumerationAnalyzer>(availableAnalyzers).AsReadOnly()));
195
[15957]196      Analyzers.CheckedItemsChanged += Analyzers_CheckedItemsChanged;
197
[15821]198      foreach (var analyzer in Analyzers) {
199        Analyzers.SetItemCheckedState(analyzer, false);
200      }
[15824]201      Analyzers.SetItemCheckedState(Analyzers.First(analyzer => analyzer is RSquaredEvaluator), true);
[15930]202
203      var grammarSymbols = Enum.GetValues(typeof(GrammarRule))
204        .Cast<GrammarRule>()
205        .Select(v => new EnumValue<GrammarRule>(v));
206
207      Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>>>(
208        GrammarSymbolsParameterName,
209        new ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>>(new CheckedItemCollection<EnumValue<GrammarRule>>(grammarSymbols))
210      ));
211      foreach (EnumValue<GrammarRule> grammarSymbol in GrammarSymbols) {
212        GrammarSymbols.SetItemCheckedState(grammarSymbol, true);
213      }
[15957]214
215      // set a default problem
216      Problem = new RegressionProblem() {
[15974]217        ProblemData = new Problems.Instances.DataAnalysis.PolyTen(seed: 1234).GenerateRegressionData()
[15957]218      };
[15722]219    }
[15712]220
[15910]221    public GrammarEnumerationAlgorithm(GrammarEnumerationAlgorithm original, Cloner cloner) : base(original, cloner) {
[15957]222      foreach (var analyzer in Analyzers.CheckedItems)
223        analyzer.Register(this);
224      Analyzers.CheckedItemsChanged += Analyzers_CheckedItemsChanged;
[15960]225
226      DistinctSentencesComplexity = new Dictionary<int, int>(original.DistinctSentencesComplexity);
227      ArchivedPhrases = new HashSet<int>(original.ArchivedPhrases);
228      OpenPhrases = cloner.Clone(original.OpenPhrases);
[15974]229      Grammar = cloner.Clone(original.Grammar);
[15960]230
231      AllGeneratedSentencesCount = original.AllGeneratedSentencesCount;
232      OverwrittenSentencesCount = original.OverwrittenSentencesCount;
233      PhraseExpansionCount = original.PhraseExpansionCount;
234
235      if (original.variableImportance != null)
236        variableImportance = new Dictionary<VariableTerminalSymbol, double>(original.variableImportance);
[15910]237    }
[15722]238    #endregion
[15712]239
[15975]240    [Storable]
[15950]241    private Dictionary<VariableTerminalSymbol, double> variableImportance;
242
[15957]243    public override void Prepare() {
244      DistinctSentencesComplexity = new Dictionary<int, int>();
[15812]245      ArchivedPhrases = new HashSet<int>();
[15821]246      AllGeneratedSentencesCount = 0;
247      OverwrittenSentencesCount = 0;
248      PhraseExpansionCount = 0;
[15746]249
[15957]250      Analyzers.OfType<RSquaredEvaluator>().First().OptimizeConstants = OptimizeConstants;
[15930]251      Grammar = new Grammar(Problem.ProblemData.AllowedInputVariables.ToArray(), GrammarSymbols.CheckedItems.Select(v => v.Value));
[15974]252      OpenPhrases = new SearchDataStore(SearchDataStructure, SearchDataStructureSize, SearchCacheSize); // Select search strategy
[15712]253
[15975]254      CalculateVariableImportances();
255
[15957]256      base.Prepare(); // this actually clears the results which will get reinitialized on Run()
257    }
258
[15975]259    private void CalculateVariableImportances() {
[15950]260      variableImportance = new Dictionary<VariableTerminalSymbol, double>();
261
262      RandomForestRegression rf = new RandomForestRegression();
263      rf.Problem = Problem;
264      rf.Start();
265      IRegressionSolution rfSolution = (RandomForestRegressionSolution)rf.Results["Random forest regression solution"].Value;
266      var rfImpacts = RegressionSolutionVariableImpactsCalculator.CalculateImpacts(
267        rfSolution,
268        RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.Training,
269        RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum.Shuffle);
270
271      // save the normalized importances
272      var sum = rfImpacts.Sum(x => x.Item2);
273      foreach (Tuple<string, double> rfImpact in rfImpacts) {
274        VariableTerminalSymbol varSym = Grammar.VarTerminals.First(v => v.StringRepresentation == rfImpact.Item1);
275        variableImportance[varSym] = rfImpact.Item2 / sum;
276      }
[15960]277    }
[15950]278
[15960]279    protected override void Run(CancellationToken cancellationToken) {
280      // do not reinitialize the algorithm if we're resuming from pause
281      if (previousExecutionState != ExecutionState.Paused) {
282        InitResults();
283        var phrase0 = new SymbolString(new[] { Grammar.StartSymbol });
284        var phrase0Hash = Grammar.Hasher.CalcHashCode(phrase0);
[15974]285
[15960]286        OpenPhrases.Store(new SearchNode(phrase0Hash, 0.0, 0.0, phrase0));
287      }
288
[15910]289      int maxSentenceLength = GetMaxSentenceLength();
[15950]290      var errorWeight = ErrorWeight;
291      var variableImportanceWeight = VariableImportanceWeight;
[15960]292      // main search loop
[15821]293      while (OpenPhrases.Count > 0) {
[15960]294        if (cancellationToken.IsCancellationRequested)
295          break;
[15746]296
[15915]297        SearchNode fetchedSearchNode = OpenPhrases.GetNext();
[15974]298
299        if (fetchedSearchNode == null)
300          continue;
301
[15915]302        SymbolString currPhrase = fetchedSearchNode.SymbolString;
[15722]303
[15915]304        OnPhraseFetched(fetchedSearchNode.Hash, currPhrase);
[15765]305
[15915]306        ArchivedPhrases.Add(fetchedSearchNode.Hash);
[15726]307
[15821]308        // expand next nonterminal symbols
[15827]309        int nonterminalSymbolIndex = currPhrase.NextNonterminalIndex();
310        NonterminalSymbol expandedSymbol = (NonterminalSymbol)currPhrase[nonterminalSymbolIndex];
[15834]311        var appliedProductions = Grammar.Productions[expandedSymbol];
[15734]312
[15827]313        for (int i = 0; i < appliedProductions.Count; i++) {
[15821]314          PhraseExpansionCount++;
[15734]315
[15827]316          SymbolString newPhrase = currPhrase.DerivePhrase(nonterminalSymbolIndex, appliedProductions[i]);
[15860]317          int newPhraseComplexity = Grammar.GetComplexity(newPhrase);
[15712]318
[15957]319          if (newPhraseComplexity > MaxComplexity)
320            continue;
[15765]321
[15957]322          var phraseHash = Grammar.Hasher.CalcHashCode(newPhrase);
[15800]323
[15957]324          OnPhraseDerived(fetchedSearchNode.Hash, fetchedSearchNode.SymbolString, phraseHash, newPhrase, expandedSymbol, appliedProductions[i]);
[15821]325
[15957]326          if (newPhrase.IsSentence()) {
327            AllGeneratedSentencesCount++;
[15821]328
[15957]329            OnSentenceGenerated(fetchedSearchNode.Hash, fetchedSearchNode.SymbolString, phraseHash, newPhrase, expandedSymbol, appliedProductions[i]);
330
331            // Is the best solution found? (only if RSquaredEvaluator is activated)
332            if (Results.ContainsKey(RSquaredEvaluator.BestTrainingQualityResultName)) {
333              double r2 = ((DoubleValue)Results[RSquaredEvaluator.BestTrainingQualityResultName].Value).Value;
334              if (r2.IsAlmost(1.0)) {
335                UpdateView(force: true);
336                return;
[15883]337              }
[15957]338            }
[15883]339
[15957]340            if (!DistinctSentencesComplexity.ContainsKey(phraseHash) || DistinctSentencesComplexity[phraseHash] > newPhraseComplexity) {
341              if (DistinctSentencesComplexity.ContainsKey(phraseHash)) OverwrittenSentencesCount++; // for analysis only
[15821]342
[15957]343              DistinctSentencesComplexity[phraseHash] = newPhraseComplexity;
344              OnDistinctSentenceGenerated(fetchedSearchNode.Hash, fetchedSearchNode.SymbolString, phraseHash, newPhrase, expandedSymbol, appliedProductions[i]);
345            }
346            UpdateView();
[15821]347
[15957]348          } else if (!OpenPhrases.Contains(phraseHash) && !ArchivedPhrases.Contains(phraseHash)) {
[15915]349
[15957]350            double r2 = GetR2(newPhrase, fetchedSearchNode.R2);
351            double phrasePriority = GetPriority(newPhrase, r2, maxSentenceLength, errorWeight, variableImportanceWeight);
[15915]352
[15957]353            SearchNode newSearchNode = new SearchNode(phraseHash, phrasePriority, r2, newPhrase);
354            OpenPhrases.Store(newSearchNode);
[15712]355          }
356        }
357      }
[15812]358      UpdateView(force: true);
[15746]359    }
[15723]360
[15950]361    protected double GetPriority(SymbolString phrase, double r2, int maxSentenceLength, double errorWeight, double variableImportanceWeight) {
362      var distinctVars = phrase.OfType<VariableTerminalSymbol>().Distinct();
363
364      var sum = 0d;
365      foreach (var v in distinctVars) {
366        sum += variableImportance[v];
367      }
368      var phraseVariableImportance = 1 - sum;
369
[15910]370      double relLength = (double)phrase.Count() / maxSentenceLength;
[15907]371      double error = 1.0 - r2;
372
[15950]373      return relLength + errorWeight * error + variableImportanceWeight * phraseVariableImportance;
[15910]374    }
375
[15915]376    private double GetR2(SymbolString phrase, double parentR2) {
377      int length = phrase.Count();
378
379      // If the only nonterminal symbol is Expr, we can need to evaluate the sentence. Otherwise
380      // the phrase has the same r2 as its parent, from which it was derived.
381      for (int i = 0; i < length; i++) {
382        if (phrase[i] is NonterminalSymbol && phrase[i] != Grammar.Expr) {
383          return parentR2;
384        }
385      }
386
387      return Grammar.EvaluatePhrase(phrase, Problem.ProblemData, OptimizeConstants);
388    }
389
[15910]390    private int GetMaxSentenceLength() {
391      SymbolString s = new SymbolString(Grammar.StartSymbol);
392
[15930]393      while (!s.IsSentence() && Grammar.GetComplexity(s) <= MaxComplexity) {
[15910]394        int expandedSymbolIndex = s.NextNonterminalIndex();
395        NonterminalSymbol expandedSymbol = (NonterminalSymbol)s[expandedSymbolIndex];
396
397        var productions = Grammar.Productions[expandedSymbol];
398        var longestProduction = productions // Find production with most terminal symbols to expand as much as possible...
399          .OrderBy(CountTerminals)          // but with lowest complexity/nonterminal count to keep complexity low.                                                                                     
400          .ThenByDescending(CountNonTerminals)
401          .First();
402
403        s = s.DerivePhrase(expandedSymbolIndex, longestProduction);
[15907]404      }
405
[15910]406      return s.Count();
407    }
[15907]408
[15910]409    private int CountTerminals(Production p) {
410      return p.Count(s => s is TerminalSymbol);
[15883]411    }
412
[15910]413    private int CountNonTerminals(Production p) {
414      return p.Count(s => s is NonterminalSymbol);
415    }
416
[15960]417    #region pause support
418    private ExecutionState previousExecutionState;
419    protected override void OnPaused() {
420      previousExecutionState = this.ExecutionState;
421      base.OnPaused();
422    }
423    protected override void OnPrepared() {
424      previousExecutionState = this.ExecutionState;
425      base.OnPrepared();
426    }
427    protected override void OnStarted() {
428      previousExecutionState = this.ExecutionState;
429      base.OnStarted();
430    }
431    protected override void OnStopped() {
432      previousExecutionState = this.ExecutionState;
[15974]433
434      if (BestTrainingSentence == null) {
435        base.OnStopped();
436        return;
437      }
438
439      var tree = Grammar.ParseSymbolicExpressionTree(BestTrainingSentence);
440      var model = new SymbolicRegressionModel(Problem.ProblemData.TargetVariable, tree, new SymbolicDataAnalysisExpressionTreeLinearInterpreter());
441      model.Scale(Problem.ProblemData);
442      var bestTrainingSolution = new SymbolicRegressionSolution(model, Problem.ProblemData);
443      Results.AddOrUpdateResult(BestTrainingModelResultName, model);
444      Results.AddOrUpdateResult(BestTrainingSolutionResultName, bestTrainingSolution);
445      Results.AddOrUpdateResult(BestComplexityResultName, new IntValue(Grammar.GetComplexity(BestTrainingSentence)));
[15960]446      base.OnStopped();
447    }
448    #endregion
449
[15821]450    #region Visualization in HL
[15746]451    // Initialize entries in result set.
452    private void InitResults() {
[15957]453      Results.Clear();
[15803]454      Results.Add(new Result(GeneratedPhrasesName, new IntValue(0)));
455      Results.Add(new Result(SearchStructureSizeName, new IntValue(0)));
[15746]456      Results.Add(new Result(GeneratedSentencesName, new IntValue(0)));
457      Results.Add(new Result(DistinctSentencesName, new IntValue(0)));
458      Results.Add(new Result(PhraseExpansionsName, new IntValue(0)));
[15821]459      Results.Add(new Result(OverwrittenSentencesName, new IntValue(0)));
[15860]460      Results.Add(new Result(AverageSentenceComplexityName, new DoubleValue(1.0)));
[15824]461      Results.Add(new Result(ExpansionsPerSecondName, "In Thousand expansions per second", new IntValue(0)));
[15712]462    }
[15746]463
464    // Update the view for intermediate results in an algorithm run.
465    private int updates;
[15812]466    private void UpdateView(bool force = false) {
[15746]467      updates++;
468
[15812]469      if (force || updates % GuiUpdateInterval == 1) {
[15803]470        ((IntValue)Results[GeneratedPhrasesName].Value).Value = ArchivedPhrases.Count;
471        ((IntValue)Results[SearchStructureSizeName].Value).Value = OpenPhrases.Count;
[15821]472        ((IntValue)Results[GeneratedSentencesName].Value).Value = AllGeneratedSentencesCount;
[15860]473        ((IntValue)Results[DistinctSentencesName].Value).Value = DistinctSentencesComplexity.Count;
[15821]474        ((IntValue)Results[PhraseExpansionsName].Value).Value = PhraseExpansionCount;
[15974]475        ((DoubleValue)Results[AverageSentenceComplexityName].Value).Value = DistinctSentencesComplexity.Count > 0
476          ? DistinctSentencesComplexity.Select(pair => pair.Value).Average()
477          : 0;
[15821]478        ((IntValue)Results[OverwrittenSentencesName].Value).Value = OverwrittenSentencesCount;
[15824]479        ((IntValue)Results[ExpansionsPerSecondName].Value).Value = (int)((PhraseExpansionCount /
480                                                                          ExecutionTime.TotalSeconds) / 1000.0);
[15746]481      }
482    }
[15821]483    #endregion
[15746]484
[15821]485    #region events
[15957]486
487    // private event handlers for analyzers
488    private void Analyzers_CheckedItemsChanged(object sender, CollectionItemsChangedEventArgs<IGrammarEnumerationAnalyzer> args) {
489      // newly added items
490      foreach (var item in args.Items.Except(args.OldItems).Union(args.OldItems.Except(args.Items))) {
491        if (Analyzers.ItemChecked(item)) {
492          item.Register(this);
493        } else {
494          item.Deregister(this);
495        }
496      }
497    }
498
[15821]499    public event EventHandler<PhraseEventArgs> PhraseFetched;
500    private void OnPhraseFetched(int hash, SymbolString symbolString) {
501      if (PhraseFetched != null) {
502        PhraseFetched(this, new PhraseEventArgs(hash, symbolString));
[15746]503      }
504    }
[15812]505
[15821]506    public event EventHandler<PhraseAddedEventArgs> PhraseDerived;
507    private void OnPhraseDerived(int parentHash, SymbolString parentSymbolString, int addedHash, SymbolString addedSymbolString, Symbol expandedSymbol, Production expandedProduction) {
508      if (PhraseDerived != null) {
509        PhraseDerived(this, new PhraseAddedEventArgs(parentHash, parentSymbolString, addedHash, addedSymbolString, expandedSymbol, expandedProduction));
510      }
[15803]511    }
[15765]512
[15821]513    public event EventHandler<PhraseAddedEventArgs> SentenceGenerated;
514    private void OnSentenceGenerated(int parentHash, SymbolString parentSymbolString, int addedHash, SymbolString addedSymbolString, Symbol expandedSymbol, Production expandedProduction) {
515      if (SentenceGenerated != null) {
516        SentenceGenerated(this, new PhraseAddedEventArgs(parentHash, parentSymbolString, addedHash, addedSymbolString, expandedSymbol, expandedProduction));
517      }
518    }
519
520    public event EventHandler<PhraseAddedEventArgs> DistinctSentenceGenerated;
521    private void OnDistinctSentenceGenerated(int parentHash, SymbolString parentSymbolString, int addedHash, SymbolString addedSymbolString, Symbol expandedSymbol, Production expandedProduction) {
522      if (DistinctSentenceGenerated != null) {
523        DistinctSentenceGenerated(this, new PhraseAddedEventArgs(parentHash, parentSymbolString, addedHash, addedSymbolString, expandedSymbol, expandedProduction));
524      }
525    }
526
527    #endregion
528
[15712]529  }
[15821]530
531  #region events for analysis
532
533  public class PhraseEventArgs : EventArgs {
534    public int Hash { get; }
535
536    public SymbolString Phrase { get; }
537
538    public PhraseEventArgs(int hash, SymbolString phrase) {
539      Hash = hash;
540      Phrase = phrase;
541    }
542  }
543
544  public class PhraseAddedEventArgs : EventArgs {
545    public int ParentHash { get; }
546    public int NewHash { get; }
547
548    public SymbolString ParentPhrase { get; }
549    public SymbolString NewPhrase { get; }
550
551    public Symbol ExpandedSymbol { get; }
552
553    public Production ExpandedProduction { get; }
554
555    public PhraseAddedEventArgs(int parentHash, SymbolString parentPhrase, int newHash, SymbolString newPhrase, Symbol expandedSymbol, Production expandedProduction) {
556      ParentHash = parentHash;
557      ParentPhrase = parentPhrase;
558      NewHash = newHash;
559      NewPhrase = newPhrase;
560      ExpandedSymbol = expandedSymbol;
561      ExpandedProduction = expandedProduction;
562    }
563  }
564
565  #endregion
[15712]566}
Note: See TracBrowser for help on using the repository browser.