#region License Information /* HeuristicLab * Copyright (C) 2002-2013 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 HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Encodings.IntegerVectorEncoding; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Random; namespace HeuristicLab.Problems.GrammaticalEvolution { /// /// DepthFirstMapper /// [Item("DepthFirstMapper", "Resolves the non-terminal symbols of the resulting phenotypic syntax tree in a depth-first manner.")] [StorableClass] public class DepthFirstMapper : GenotypeToPhenotypeMapper { [StorableConstructor] protected DepthFirstMapper(bool deserializing) : base(deserializing) { } protected DepthFirstMapper(DepthFirstMapper original, Cloner cloner) : base(original, cloner) { } public DepthFirstMapper() : base() { } public override IDeepCloneable Clone(Cloner cloner) { return new DepthFirstMapper(this, cloner); } /// /// Maps a genotype (an integer vector) to a phenotype (a symbolic expression tree). /// Depth-first approach. /// /// grammar definition /// integer vector, which should be mapped to a tree /// phenotype (a symbolic expression tree) public override SymbolicExpressionTree Map(ISymbolicExpressionGrammar grammar, IntegerVector genotype) { SymbolicExpressionTree tree = new SymbolicExpressionTree(); var rootNode = (SymbolicExpressionTreeTopLevelNode)grammar.ProgramRootSymbol.CreateTreeNode(); if (rootNode.HasLocalParameters) rootNode.ResetLocalParameters(new MersenneTwister()); var startNode = (SymbolicExpressionTreeTopLevelNode)grammar.StartSymbol.CreateTreeNode(); if (startNode.HasLocalParameters) startNode.ResetLocalParameters(new MersenneTwister()); rootNode.AddSubtree(startNode); tree.Root = rootNode; MapDepthFirstIteratively(startNode, genotype, grammar, genotype.Length, new MersenneTwister()); return tree; } /// /// Genotype-to-Phenotype mapper (iterative depth-first approach, by using a stack -> LIFO). /// /// first node of the tree with arity 1 /// integer vector, which should be mapped to a tree /// grammar to determine the allowed child symbols for each node /// maximum allowed subtrees (= number of used genomes) /// random number generator private void MapDepthFirstIteratively(ISymbolicExpressionTreeNode startNode, IntegerVector genotype, ISymbolicExpressionGrammar grammar, int maxSubtreeCount, IRandom random) { Stack> stack = new Stack>(); // tuples of int genotypeIndex = 0; int currSubtreeCount = 1; stack.Push(new Tuple(startNode, 1)); while ((currSubtreeCount < maxSubtreeCount) && (stack.Count > 0)) { // get next node from stack and re-push it, if this node still has unhandled subtrees ... Tuple current = stack.Pop(); if (current.Item2 > 1) { stack.Push(new Tuple(current.Item1, current.Item2 - 1)); } var newNode = GetNewChildNode(current.Item1, genotype, grammar, genotypeIndex, random); int arity = SampleArity(random, newNode, maxSubtreeCount - currSubtreeCount); if (arity < 0) { current.Item1.AddSubtree(GetRandomTerminalNode(current.Item1, grammar, random)); } else { current.Item1.AddSubtree(newNode); genotypeIndex++; currSubtreeCount += arity; if (arity > 0) { // new node has subtrees so push it onto the stack stack.Push(new Tuple(newNode, arity)); } } } // maximum allowed subtree count was already reached, but there are still // incomplete subtrees (non-terminal symbols) in the tree // -> fill them with terminal symbols while (stack.Count > 0) { Tuple current = stack.Pop(); if (current.Item2 > 1) { stack.Push(new Tuple(current.Item1, current.Item2 - 1)); } current.Item1.AddSubtree(GetRandomTerminalNode(current.Item1, grammar, random)); } } } }