using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Text.RegularExpressions; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.PluginInfrastructure; namespace HeuristicLab.Problems.GrammaticalOptimization { [NonDiscoverableType] [StorableClass] [Item("GenericSymbExprGrammar", "Represents a general grammar for grammatical optimization problems.")] public class GenericSymbExprGrammar : SymbolicExpressionGrammar { [StorableClass] [Item("GenericSymbol", "")] public sealed class GenericSymbol : Symbol { private readonly int minimumArity = 1; private readonly int maximumArity = byte.MaxValue; public override int MinimumArity { get { return minimumArity; } } public override int MaximumArity { get { return maximumArity; } } [StorableConstructor] private GenericSymbol(bool deserializing) : base(deserializing) { } private GenericSymbol(GenericSymbol original, Cloner cloner) : base(original, cloner) { } public override IDeepCloneable Clone(Cloner cloner) { return new GenericSymbol(this, cloner); } public GenericSymbol(char s, int minArity, int maxArity) : base(s.ToString(), string.Empty) { this.minimumArity = minArity; this.maximumArity = maxArity; } } [StorableConstructor] public GenericSymbExprGrammar(bool deserializing) : base(deserializing) { } public GenericSymbExprGrammar(SymbolicExpressionGrammar original, Cloner cloner) : base(original, cloner) { } public GenericSymbExprGrammar(IGrammar grammar) : base(ItemAttribute.GetName(typeof(GenericSymbExprGrammar)), ItemAttribute.GetDescription(typeof(GenericSymbExprGrammar))) { var ntSymbs = new List(); var tSymbs = new List(); // for terminal and nonterminal symbol in the grammar create a symbol class // for non-terminals set the arity and the allowed children // for terminals set arity to 0 and allowed children to empty foreach (var nt in grammar.NonTerminalSymbols) { var ntSymb = CreateSymbol(grammar, nt); AddSymbol(ntSymb); SetSubtreeCount(ntSymb, ntSymb.MinimumArity, ntSymb.MaximumArity); ntSymbs.Add(ntSymb); } foreach (var t in grammar.TerminalSymbols) { var tSymb = new GenericSymbol(t, 0, 0); AddSymbol(tSymb); SetSubtreeCount(tSymb, 0, 0); tSymbs.Add(tSymb); } Func findSymb = (char s) => { var selectedSymb = ntSymbs.SingleOrDefault(symb => symb.Name == s.ToString()); if (selectedSymb != null) return selectedSymb; return tSymbs.SingleOrDefault(symb => symb.Name == s.ToString()); }; // set the sentence symbol as the allowed start symbol AddAllowedChildSymbol(StartSymbol, findSymb(grammar.SentenceSymbol)); foreach (var nt in ntSymbs) { // either all alts are only a single symbol // or all alts only use a single symbol (see assertion in CreateSymbol) var alts = grammar.GetAlternatives(nt.Name[0]); // all symbols only have a single character name Debug.Assert(alts.All(alt => alt.Length == 1 || alt.Distinct().Count() == 1)); foreach (var alt in alts) { Debug.Assert(alt.All(ch => ch == alt[0])); AddAllowedChildSymbol(nt, findSymb(alt.First())); } } } private GenericSymbol CreateSymbol(IGrammar g, char s) { var minArity = g.GetAlternatives(s).Select(alt => alt.Length).Min(); var maxArity = g.GetAlternatives(s).Select(alt => alt.Length).Max(); // either the min and max arity is 1 or the alternatives all use the same symbol (hl doesn't know about dependencies between positions in the alternative Debug.Assert( (minArity == 1 && maxArity == 1) || g.GetAlternatives(s).Select(alt => alt.Distinct()).All(alt => alt.Count() == 1)); var symb = new GenericSymbol(s, minArity, maxArity); return symb; } public override IDeepCloneable Clone(Cloner cloner) { return new GenericSymbExprGrammar(this, cloner); } } }