Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2886: Refactor RSquaredEvaluator as a standalone ParameterizedNamedItem which is a parameter of the algorithm. Implement BestSolutionAnalyzer analyzer for quality statistics. Add license headers where missing.

File size: 23.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Threading;
26using HeuristicLab.Collections;
27using HeuristicLab.Common;
28using HeuristicLab.Core;
29using HeuristicLab.Data;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
33using HeuristicLab.Problems.DataAnalysis;
34using HeuristicLab.Problems.DataAnalysis.Symbolic;
35using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
36
37namespace HeuristicLab.Algorithms.DataAnalysis.SymRegGrammarEnumeration {
38  [Item("Grammar Enumeration Symbolic Regression", "Iterates all possible model structures for a fixed grammar.")]
39  [StorableClass]
40  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 250)]
41  public class GrammarEnumerationAlgorithm : FixedDataAnalysisAlgorithm<IRegressionProblem> {
42    #region properties and result names
43    private readonly string SearchStructureSizeName = "Search Structure Size";
44    private readonly string GeneratedPhrasesName = "Generated/Archived Phrases";
45    private readonly string GeneratedSentencesName = "Generated Sentences";
46    private readonly string DistinctSentencesName = "Distinct Sentences";
47    private readonly string PhraseExpansionsName = "Phrase Expansions";
48    private readonly string AverageSentenceComplexityName = "Avg. Sentence Complexity among Distinct";
49    private readonly string OverwrittenSentencesName = "Sentences overwritten";
50    private readonly string AnalyzersParameterName = "Analyzers";
51    private readonly string ExpansionsPerSecondName = "Expansions per second";
52
53    private readonly string EvaluatorParameterName = "Evaluator";
54
55    private readonly string ErrorWeightParameterName = "Error Weight";
56    private readonly string SearchDataStructureParameterName = "Search Data Structure";
57    private readonly string MaxComplexityParameterName = "Max. Complexity";
58    private readonly string GuiUpdateIntervalParameterName = "GUI Update Interval";
59    private readonly string GrammarSymbolsParameterName = "Grammar Symbols";
60    private readonly string SearchDataStructureSizeParameterName = "Search Data Structure Size";
61
62    // result names
63    public static readonly string BestTrainingModelResultName = "Best model (Training)";
64    public static readonly string BestTrainingSolutionResultName = "Best solution (Training)";
65    public static readonly string BestComplexityResultName = "Best solution complexity";
66
67    public override bool SupportsPause { get { return true; } }
68
69    public IFixedValueParameter<RSquaredEvaluator> EvaluatorParameter {
70      get { return (IFixedValueParameter<RSquaredEvaluator>)Parameters[EvaluatorParameterName]; }
71    }
72
73    public RSquaredEvaluator Evaluator {
74      get { return EvaluatorParameter.Value; }
75    }
76
77    protected IFixedValueParameter<IntValue> MaxComplexityParameter {
78      get { return (IFixedValueParameter<IntValue>)Parameters[MaxComplexityParameterName]; }
79    }
80
81    public int MaxComplexity {
82      get { return MaxComplexityParameter.Value.Value; }
83      set { MaxComplexityParameter.Value.Value = value; }
84    }
85
86    protected IFixedValueParameter<DoubleValue> ErrorWeightParameter {
87      get { return (IFixedValueParameter<DoubleValue>)Parameters[ErrorWeightParameterName]; }
88    }
89
90    public double ErrorWeight {
91      get { return ErrorWeightParameter.Value.Value; }
92      set { ErrorWeightParameter.Value.Value = value; }
93    }
94
95    protected IFixedValueParameter<IntValue> GuiUpdateIntervalParameter {
96      get { return (IFixedValueParameter<IntValue>)Parameters[GuiUpdateIntervalParameterName]; }
97    }
98
99    public int GuiUpdateInterval {
100      get { return GuiUpdateIntervalParameter.Value.Value; }
101      set { GuiUpdateIntervalParameter.Value.Value = value; }
102    }
103
104    protected IFixedValueParameter<EnumValue<StorageType>> SearchDataStructureParameter {
105      get { return (IFixedValueParameter<EnumValue<StorageType>>)Parameters[SearchDataStructureParameterName]; }
106    }
107
108    public IFixedValueParameter<IntValue> SearchDataStructureSizeParameter {
109      get { return (IFixedValueParameter<IntValue>)Parameters[SearchDataStructureSizeParameterName]; }
110    }
111
112    public int SearchDataStructureSize {
113      get { return SearchDataStructureSizeParameter.Value.Value; }
114      set { SearchDataStructureSizeParameter.Value.Value = value; }
115    }
116
117    public StorageType SearchDataStructure {
118      get { return SearchDataStructureParameter.Value.Value; }
119      set { SearchDataStructureParameter.Value.Value = value; }
120    }
121
122    public IFixedValueParameter<ReadOnlyCheckedItemCollection<IGrammarEnumerationAnalyzer>> AnalyzersParameter {
123      get { return (IFixedValueParameter<ReadOnlyCheckedItemCollection<IGrammarEnumerationAnalyzer>>)Parameters[AnalyzersParameterName]; }
124    }
125
126    public ICheckedItemCollection<IGrammarEnumerationAnalyzer> Analyzers {
127      get { return AnalyzersParameter.Value; }
128    }
129
130    public IFixedValueParameter<ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>>> GrammarSymbolsParameter {
131      get { return (IFixedValueParameter<ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>>>)Parameters[GrammarSymbolsParameterName]; }
132    }
133
134    public ReadOnlyCheckedItemCollection<EnumValue<GrammarRule>> GrammarSymbols {
135      get { return GrammarSymbolsParameter.Value; }
136    }
137
138    [Storable]
139    public SymbolList BestTrainingSentence { get; set; }     // Currently set in RSquaredEvaluator: quite hacky, but makes testing much easier for now...
140    #endregion
141
142    [Storable]
143    public Dictionary<int, int> DistinctSentencesComplexity { get; private set; }  // Semantically distinct sentences and their length in a run.
144
145    [Storable]
146    public HashSet<int> ArchivedPhrases { get; private set; }
147
148    [Storable]
149    internal SearchDataStore OpenPhrases { get; private set; }           // Stack/Queue/etc. for fetching the next node in the search tree. 
150
151    [Storable]
152    public int MaxSentenceLength { get; private set; }
153
154    #region execution stats
155    [Storable]
156    public int AllGeneratedSentencesCount { get; private set; }
157
158    [Storable]
159    public int OverwrittenSentencesCount { get; private set; } // It is not guaranteed that shorter solutions are found first.
160                                                               // When longer solutions are overwritten with shorter ones,
161                                                               // this counter is increased.
162    [Storable]
163    public int PhraseExpansionCount { get; private set; }      // Number, how many times a nonterminal symbol is replaced with a production rule.
164    #endregion
165
166    [Storable]
167    public Grammar Grammar { get; private set; }
168
169    #region ctors
170    public override IDeepCloneable Clone(Cloner cloner) {
171      return new GrammarEnumerationAlgorithm(this, cloner);
172    }
173
174    [StorableConstructor]
175    protected GrammarEnumerationAlgorithm(bool deserializing) : base(deserializing) { }
176
177    private void RegisterEvents() {
178      // re-wire analyzer events
179      foreach (var analyzer in Analyzers.CheckedItems)
180        analyzer.Register(this);
181      Analyzers.CheckedItemsChanged += Analyzers_CheckedItemsChanged;
182
183      SearchDataStructureParameter.Value.ValueChanged += (o, e) => Prepare();
184      SearchDataStructureSizeParameter.Value.ValueChanged += (o, e) => Prepare();
185    }
186
187    private void DeregisterEvents() {
188      foreach (var analyzer in Analyzers.CheckedItems)
189        analyzer.Register(this);
190      Analyzers.CheckedItemsChanged -= Analyzers_CheckedItemsChanged;
191
192      SearchDataStructureParameter.Value.ValueChanged -= (o, e) => Prepare();
193      SearchDataStructureSizeParameter.Value.ValueChanged -= (o, e) => Prepare();
194    }
195
196    [StorableHook(HookType.AfterDeserialization)]
197    private void AfterDeserialization() {
198      RegisterEvents();
199    }
200
201    public GrammarEnumerationAlgorithm() {
202      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)));
203      Parameters.Add(new FixedValueParameter<IntValue>(MaxComplexityParameterName, "The maximum number of variable symbols in a sentence.", new IntValue(12)));
204      Parameters.Add(new FixedValueParameter<IntValue>(GuiUpdateIntervalParameterName, "Number of generated sentences, until GUI is refreshed.", new IntValue(5000)));
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.SortedSet)));
207      Parameters.Add(new FixedValueParameter<RSquaredEvaluator>(EvaluatorParameterName, new RSquaredEvaluator()));
208
209      SearchDataStructureParameter.Value.ValueChanged += (o, e) => Prepare();
210      SearchDataStructureSizeParameter.Value.ValueChanged += (o, e) => Prepare();
211
212      var availableAnalyzers = new IGrammarEnumerationAnalyzer[] {
213        new SearchGraphVisualizer(),
214        new SentenceLogger(),
215        new BestSolutionAnalyzer()
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 BestSolutionAnalyzer), 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    #endregion
262
263    public override void Prepare() {
264      DistinctSentencesComplexity = new Dictionary<int, int>();
265      ArchivedPhrases = new HashSet<int>();
266      AllGeneratedSentencesCount = 0;
267      OverwrittenSentencesCount = 0;
268      PhraseExpansionCount = 0;
269
270      Grammar = new Grammar(Problem.ProblemData.AllowedInputVariables.ToArray(), GrammarSymbols.CheckedItems.Select(v => v.Value));
271      OpenPhrases = new SearchDataStore(SearchDataStructure, SearchDataStructureSize); // Select search strategy
272      base.Prepare(); // this actually clears the results which will get reinitialized on Run()
273    }
274
275    protected override void Run(CancellationToken cancellationToken) {
276      // do not reinitialize the algorithm if we're resuming from pause
277      if (previousExecutionState != ExecutionState.Paused) {
278        InitResults();
279        var phrase0 = new SymbolList(new[] { Grammar.StartSymbol });
280        var phrase0Hash = Grammar.Hasher.CalcHashCode(phrase0);
281
282        OpenPhrases.Store(new SearchNode(phrase0Hash, 0.0, 0.0, phrase0));
283      }
284
285      MaxSentenceLength = Grammar.GetMaxSentenceLength(MaxComplexity);
286      var errorWeight = ErrorWeight;
287      var evaluator = EvaluatorParameter.Value;
288      var problemData = Problem.ProblemData;
289
290      // main search loop
291      while (OpenPhrases.Count > 0) {
292        if (cancellationToken.IsCancellationRequested)
293          break;
294
295        SearchNode fetchedSearchNode = OpenPhrases.GetNext();
296
297        if (fetchedSearchNode == null)
298          continue;
299
300        SymbolList currPhrase = fetchedSearchNode.SymbolList;
301
302        OnPhraseFetched(fetchedSearchNode.Hash, currPhrase);
303
304        ArchivedPhrases.Add(fetchedSearchNode.Hash);
305
306        // expand next nonterminal symbols
307        int nonterminalSymbolIndex = currPhrase.NextNonterminalIndex();
308        NonterminalSymbol expandedSymbol = (NonterminalSymbol)currPhrase[nonterminalSymbolIndex];
309        var appliedProductions = Grammar.Productions[expandedSymbol];
310
311        for (int i = 0; i < appliedProductions.Count; i++) {
312          PhraseExpansionCount++;
313
314          SymbolList newPhrase = currPhrase.DerivePhrase(nonterminalSymbolIndex, appliedProductions[i]);
315          int newPhraseComplexity = newPhrase.Complexity;
316
317          if (newPhraseComplexity > MaxComplexity)
318            continue;
319
320          var phraseHash = Grammar.Hasher.CalcHashCode(newPhrase);
321
322          OnPhraseDerived(fetchedSearchNode.Hash, fetchedSearchNode.SymbolList, phraseHash, newPhrase, expandedSymbol, appliedProductions[i]);
323
324          if (newPhrase.IsSentence()) {
325            AllGeneratedSentencesCount++;
326
327            OnSentenceGenerated(fetchedSearchNode.Hash, fetchedSearchNode.SymbolList, phraseHash, newPhrase, expandedSymbol, appliedProductions[i]);
328
329            // Is the best solution found? (only if RSquaredEvaluator is activated)
330            //if (Results.ContainsKey(RSquaredEvaluator.BestTrainingQualityResultName)) {
331            //  double r2 = ((DoubleValue)Results[RSquaredEvaluator.BestTrainingQualityResultName].Value).Value;
332            //  if (r2.IsAlmost(1.0)) {
333            //    UpdateView(force: true);
334            //    return;
335            //  }
336            //}
337
338            if (!DistinctSentencesComplexity.ContainsKey(phraseHash) || DistinctSentencesComplexity[phraseHash] > newPhraseComplexity) {
339              if (DistinctSentencesComplexity.ContainsKey(phraseHash)) OverwrittenSentencesCount++; // for analysis only
340
341              DistinctSentencesComplexity[phraseHash] = newPhraseComplexity;
342              OnDistinctSentenceGenerated(fetchedSearchNode.Hash, fetchedSearchNode.SymbolList, phraseHash, newPhrase, expandedSymbol, appliedProductions[i]);
343            }
344            UpdateView();
345
346          } else if (!OpenPhrases.Contains(phraseHash) && !ArchivedPhrases.Contains(phraseHash)) {
347            double r2 = IsCompleteSentence(newPhrase) ? evaluator.Evaluate(problemData, Grammar, newPhrase) : fetchedSearchNode.R2;
348            double phrasePriority = GetPriority(newPhrase, r2);
349
350            SearchNode newSearchNode = new SearchNode(phraseHash, phrasePriority, r2, newPhrase);
351            OpenPhrases.Store(newSearchNode);
352          }
353        }
354      }
355      UpdateView(force: true);
356    }
357
358    protected static double GetPriority(SymbolList phrase, double r2) {
359      return (1 - r2) * phrase.Count;
360    }
361
362    private bool IsCompleteSentence(SymbolList phrase) {
363      return !phrase.Any(x => x is NonterminalSymbol && x != Grammar.Expr);
364    }
365
366    #region pause support
367    private ExecutionState previousExecutionState;
368
369    protected override void OnPaused() {
370      previousExecutionState = this.ExecutionState;
371      base.OnPaused();
372    }
373
374    protected override void OnPrepared() {
375      previousExecutionState = this.ExecutionState;
376      base.OnPrepared();
377    }
378
379    protected override void OnStarted() {
380      previousExecutionState = this.ExecutionState;
381      base.OnStarted();
382    }
383
384    protected override void OnStopped() {
385      previousExecutionState = this.ExecutionState;
386      // free memory at the end of the run (this saves a lot of memory)
387      ArchivedPhrases.Clear();
388      OpenPhrases.Clear();
389      DistinctSentencesComplexity.Clear();
390
391      if (BestTrainingSentence == null) {
392        base.OnStopped();
393        return;
394      }
395
396      var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
397      var tree = Grammar.ParseSymbolicExpressionTree(BestTrainingSentence);
398      var model = new SymbolicRegressionModel(Problem.ProblemData.TargetVariable, tree, interpreter);
399
400      var iterations = EvaluatorParameter.Value.ConstantOptimizationIterations;
401      var applyLinearScaling = EvaluatorParameter.Value.ApplyLinearScaling;
402
403      SymbolicRegressionConstantOptimizationEvaluator.OptimizeConstants(
404        interpreter,
405        model.SymbolicExpressionTree,
406        Problem.ProblemData,
407        Problem.ProblemData.TrainingIndices,
408        applyLinearScaling: applyLinearScaling,
409        maxIterations: iterations,
410        updateVariableWeights: false,
411        updateConstantsInTree: true);
412
413      model.Scale(Problem.ProblemData);
414      var bestTrainingSolution = new SymbolicRegressionSolution(model, Problem.ProblemData);
415
416      Results.AddOrUpdateResult(BestTrainingModelResultName, model);
417      Results.AddOrUpdateResult(BestTrainingSolutionResultName, bestTrainingSolution);
418      Results.AddOrUpdateResult(BestComplexityResultName, new IntValue(BestTrainingSentence.Complexity));
419      base.OnStopped();
420    }
421    #endregion
422
423    #region Visualization in HL
424    // Initialize entries in result set.
425    private void InitResults() {
426      Results.Clear();
427      Results.Add(new Result(GeneratedPhrasesName, new IntValue(0)));
428      Results.Add(new Result(SearchStructureSizeName, new IntValue(0)));
429      Results.Add(new Result(GeneratedSentencesName, new IntValue(0)));
430      Results.Add(new Result(DistinctSentencesName, new IntValue(0)));
431      Results.Add(new Result(PhraseExpansionsName, new IntValue(0)));
432      Results.Add(new Result(OverwrittenSentencesName, new IntValue(0)));
433      Results.Add(new Result(AverageSentenceComplexityName, new DoubleValue(1.0)));
434      Results.Add(new Result(ExpansionsPerSecondName, "In Thousand expansions per second", new IntValue(0)));
435    }
436
437    // Update the view for intermediate results in an algorithm run.
438    private int updates;
439    private void UpdateView(bool force = false) {
440      updates++;
441
442      if (force || updates % GuiUpdateInterval == 1) {
443        ((IntValue)Results[GeneratedPhrasesName].Value).Value = ArchivedPhrases.Count;
444        ((IntValue)Results[SearchStructureSizeName].Value).Value = OpenPhrases.Count;
445        ((IntValue)Results[GeneratedSentencesName].Value).Value = AllGeneratedSentencesCount;
446        ((IntValue)Results[DistinctSentencesName].Value).Value = DistinctSentencesComplexity.Count;
447        ((IntValue)Results[PhraseExpansionsName].Value).Value = PhraseExpansionCount;
448        ((DoubleValue)Results[AverageSentenceComplexityName].Value).Value = DistinctSentencesComplexity.Count > 0
449          ? DistinctSentencesComplexity.Select(pair => pair.Value).Average()
450          : 0;
451        ((IntValue)Results[OverwrittenSentencesName].Value).Value = OverwrittenSentencesCount;
452        ((IntValue)Results[ExpansionsPerSecondName].Value).Value = (int)((PhraseExpansionCount /
453                                                                          ExecutionTime.TotalSeconds) / 1000.0);
454      }
455    }
456    #endregion
457
458    #region events
459
460    // private event handlers for analyzers
461    private void Analyzers_CheckedItemsChanged(object sender, CollectionItemsChangedEventArgs<IGrammarEnumerationAnalyzer> args) {
462      // newly added items
463      foreach (var item in args.Items.Except(args.OldItems).Union(args.OldItems.Except(args.Items))) {
464        if (Analyzers.ItemChecked(item)) {
465          item.Register(this);
466        } else {
467          item.Deregister(this);
468        }
469      }
470    }
471
472    public event EventHandler<PhraseEventArgs> PhraseFetched;
473    private void OnPhraseFetched(int hash, SymbolList phrase) {
474      if (PhraseFetched != null) {
475        PhraseFetched(this, new PhraseEventArgs(hash, phrase));
476      }
477    }
478
479    public event EventHandler<PhraseAddedEventArgs> PhraseDerived;
480    private void OnPhraseDerived(int parentHash, SymbolList parentSymbolList, int addedHash, SymbolList addedSymbolList, Symbol expandedSymbol, SymbolList expandedProduction) {
481      if (PhraseDerived != null) {
482        PhraseDerived(this, new PhraseAddedEventArgs(parentHash, parentSymbolList, addedHash, addedSymbolList, expandedSymbol, expandedProduction));
483      }
484    }
485
486    public event EventHandler<PhraseAddedEventArgs> SentenceGenerated;
487    private void OnSentenceGenerated(int parentHash, SymbolList parentSymbolList, int addedHash, SymbolList addedSymbolList, Symbol expandedSymbol, SymbolList expandedProduction) {
488      if (SentenceGenerated != null) {
489        SentenceGenerated(this, new PhraseAddedEventArgs(parentHash, parentSymbolList, addedHash, addedSymbolList, expandedSymbol, expandedProduction));
490      }
491    }
492
493    public event EventHandler<PhraseAddedEventArgs> DistinctSentenceGenerated;
494    private void OnDistinctSentenceGenerated(int parentHash, SymbolList parentSymbolList, int addedHash, SymbolList addedSymbolList, Symbol expandedSymbol, SymbolList expandedProduction) {
495      if (DistinctSentenceGenerated != null) {
496        DistinctSentenceGenerated(this, new PhraseAddedEventArgs(parentHash, parentSymbolList, addedHash, addedSymbolList, expandedSymbol, expandedProduction));
497      }
498    }
499
500    #endregion
501
502  }
503
504  #region events for analysis
505
506  public class PhraseEventArgs : EventArgs {
507    public int Hash { get; }
508
509    public SymbolList Phrase { get; }
510
511    public PhraseEventArgs(int hash, SymbolList phrase) {
512      Hash = hash;
513      Phrase = phrase;
514    }
515  }
516
517  public class PhraseAddedEventArgs : EventArgs {
518    public int ParentHash { get; }
519    public int NewHash { get; }
520
521    public SymbolList ParentPhrase { get; }
522    public SymbolList NewPhrase { get; }
523
524    public Symbol ExpandedSymbol { get; }
525
526    public SymbolList ExpandedProduction { get; }
527
528    public PhraseAddedEventArgs(int parentHash, SymbolList parentPhrase, int newHash, SymbolList newPhrase, Symbol expandedSymbol, SymbolList expandedProduction) {
529      ParentHash = parentHash;
530      ParentPhrase = parentPhrase;
531      NewHash = newHash;
532      NewPhrase = newPhrase;
533      ExpandedSymbol = expandedSymbol;
534      ExpandedProduction = expandedProduction;
535    }
536  }
537
538  #endregion
539}
Note: See TracBrowser for help on using the repository browser.