Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2886: Register algorithm events after deserialization.

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