#region License Information
/* HeuristicLab
* Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
public static class GrammarUtils {
private static IEnumerable GetTopmostSymbols(this ISymbolicExpressionGrammarBase grammar) {
// build parents list so we can find out the topmost symbol(s)
var parents = new Dictionary>();
foreach (var symbol in grammar.Symbols.Where(x => grammar.GetMinimumSubtreeCount(x) > 0)) {
var minSubtreeCount = grammar.GetMinimumSubtreeCount(symbol);
for (int argIndex = 0; argIndex < minSubtreeCount; ++argIndex) {
foreach (var childSymbol in grammar.GetAllowedActiveSymbols(symbol, argIndex)) {
if (!parents.ContainsKey(childSymbol))
parents[childSymbol] = new List();
parents[childSymbol].Add(symbol);
}
}
}
// the topmost symbols have no parents
return parents.Values.SelectMany(x => x).Distinct().Where(x => !parents.ContainsKey(x));
}
private static IReadOnlyCollection IterateBreadthReverse(this ISymbolicExpressionGrammarBase grammar, ISymbol topSymbol) {
// sort symbols in reverse breadth order (starting from the topSymbol)
// each symbol is visited only once (this avoids infinite recursion)
var symbols = new List { topSymbol };
var visited = new HashSet { topSymbol };
int i = 0;
while (i < symbols.Count) {
var symbol = symbols[i];
var minSubtreeCount = grammar.GetMinimumSubtreeCount(symbol);
for (int argIndex = 0; argIndex < minSubtreeCount; ++argIndex) {
foreach (var childSymbol in grammar.GetAllowedActiveSymbols(symbol, argIndex)) {
if (grammar.GetMinimumSubtreeCount(childSymbol) == 0)
continue;
if (visited.Add(childSymbol))
symbols.Add(childSymbol);
}
}
++i;
}
symbols.Reverse();
return symbols;
}
private static IEnumerable GetAllowedActiveSymbols(this ISymbolicExpressionGrammarBase grammar, ISymbol symbol, int argIndex) {
return grammar.GetAllowedChildSymbols(symbol, argIndex).Where(s => s.InitialFrequency > 0);
}
public static void CalculateMinimumExpressionLengths(ISymbolicExpressionGrammarBase grammar,
Dictionary minimumExpressionLengths) {
minimumExpressionLengths.Clear();
//terminal symbols => minimum expression length = 1
foreach (var s in grammar.Symbols) {
if (grammar.GetMinimumSubtreeCount(s) == 0)
minimumExpressionLengths[s.Name] = 1;
else
minimumExpressionLengths[s.Name] = int.MaxValue;
}
foreach (var topSymbol in grammar.GetTopmostSymbols()) {
// get all symbols below in reverse breadth order
// this way we ensure lengths are calculated bottom-up
var symbols = grammar.IterateBreadthReverse(topSymbol);
foreach (var symbol in symbols) {
long minLength = 1;
for (int argIndex = 0; argIndex < grammar.GetMinimumSubtreeCount(symbol); ++argIndex) {
long length = grammar.GetAllowedActiveSymbols(symbol, argIndex)
.Where(x => minimumExpressionLengths.ContainsKey(x.Name))
.Select(x => minimumExpressionLengths[x.Name]).DefaultIfEmpty(int.MaxValue).Min();
minLength += length;
}
int oldLength;
if (minimumExpressionLengths.TryGetValue(symbol.Name, out oldLength))
minLength = Math.Min(minLength, oldLength);
minimumExpressionLengths[symbol.Name] = (int)Math.Min(int.MaxValue, minLength);
}
// correction step for cycles
bool changed = true;
while (changed) {
changed = false;
foreach (var symbol in symbols) {
long minLength = Enumerable.Range(0, grammar.GetMinimumSubtreeCount(symbol))
.Sum(x => grammar.GetAllowedActiveSymbols(symbol, x)
.Select(s => (long)minimumExpressionLengths[s.Name]).DefaultIfEmpty(int.MaxValue).Min()) + 1;
if (minLength < minimumExpressionLengths[symbol.Name]) {
minimumExpressionLengths[symbol.Name] = (int)Math.Min(minLength, int.MaxValue);
changed = true;
}
}
}
}
}
public static void CalculateMinimumExpressionDepth(ISymbolicExpressionGrammarBase grammar,
Dictionary minimumExpressionDepths) {
minimumExpressionDepths.Clear();
//terminal symbols => minimum expression depth = 1
foreach (var s in grammar.Symbols) {
if (grammar.GetMinimumSubtreeCount(s) == 0)
minimumExpressionDepths[s.Name] = 1;
else
minimumExpressionDepths[s.Name] = int.MaxValue;
}
foreach (var topSymbol in grammar.GetTopmostSymbols()) {
// get all symbols below in reverse breadth order
// this way we ensure lengths are calculated bottom-up
var symbols = grammar.IterateBreadthReverse(topSymbol);
foreach (var symbol in symbols) {
long minDepth = -1;
for (int argIndex = 0; argIndex < grammar.GetMinimumSubtreeCount(symbol); ++argIndex) {
long depth = grammar.GetAllowedActiveSymbols(symbol, argIndex)
.Where(x => minimumExpressionDepths.ContainsKey(x.Name))
.Select(x => (long)minimumExpressionDepths[x.Name]).DefaultIfEmpty(int.MaxValue).Min() + 1;
minDepth = Math.Max(minDepth, depth);
}
int oldDepth;
if (minimumExpressionDepths.TryGetValue(symbol.Name, out oldDepth))
minDepth = Math.Min(minDepth, oldDepth);
minimumExpressionDepths[symbol.Name] = (int)Math.Min(int.MaxValue, minDepth);
}
// correction step for cycles
bool changed = true;
while (changed) {
changed = false;
foreach (var symbol in symbols) {
long minDepth = Enumerable.Range(0, grammar.GetMinimumSubtreeCount(symbol))
.Max(x => grammar.GetAllowedActiveSymbols(symbol, x)
.Select(s => (long)minimumExpressionDepths[s.Name]).DefaultIfEmpty(int.MaxValue).Min()) + 1;
if (minDepth < minimumExpressionDepths[symbol.Name]) {
minimumExpressionDepths[symbol.Name] = (int)Math.Min(minDepth, int.MaxValue);
changed = true;
}
}
}
}
}
}
}