#region License Information /* HeuristicLab * Copyright (C) 2002-2019 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 HEAL.Attic; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding; using HeuristicLab.Parameters; using HeuristicLab.Problems.DataAnalysis.Symbolic; using HeuristicLab.Random; using System.Collections.Generic; using System.Linq; namespace HeuristicLab.Algorithms.EvolvmentModelsOfModels { [Item("EMMChangeNodeTypeManipulation", "Selects a random tree node and changes the symbol.")] [StorableType("990D3946-7F06-48B4-B8DB-F8E308D6304D")] public sealed class EMMMutators : SymbolicExpressionTreeManipulator { private const int MAX_TRIES = 100; private const string ModelSetParameterName = "Models"; private const string ClusterNumberParameterName = "ClusterNumber"; private const string MapParameterName = "Map"; public ILookupParameter> ModelSetParameter { get { return (ILookupParameter>)Parameters[ModelSetParameterName]; } } public ILookupParameter> ClusterNumberParameter { get { return (ILookupParameter>)Parameters[ClusterNumberParameterName]; } } public ILookupParameter>> MapParameter { get { return (ILookupParameter>>)Parameters[MapParameterName]; } } public ItemList ModelSet => ModelSetParameter.ActualValue; public ItemList ClusterNumber => ClusterNumberParameter.ActualValue; public ItemList> Map => MapParameter.ActualValue; [StorableConstructor] private EMMMutators(StorableConstructorFlag _) : base(_) { } private EMMMutators(EMMMutators original, Cloner cloner) : base(original, cloner) { } public EMMMutators() : base() { Parameters.Add(new LookupParameter>(ModelSetParameterName)); Parameters.Add(new LookupParameter>(ClusterNumberParameterName)); Parameters.Add(new LookupParameter>>(MapParameterName)); } public override IDeepCloneable Clone(Cloner cloner) { return new EMMMutators(this, cloner); } protected override void Manipulate(IRandom random, ISymbolicExpressionTree symbolicExpressionTree) { EMMMutatorsPart(random, symbolicExpressionTree, ModelSet, ClusterNumber, Map); } public static void EMMMutatorsPart(IRandom random, ISymbolicExpressionTree symbolicExpressionTree, ItemList modelSet, ItemList clusterNumber, ItemList> map) { List allowedSymbols = new List(); ISymbolicExpressionTreeNode parent; int childIndex; ISymbolicExpressionTreeNode child; // repeat until a fitting parent and child are found (MAX_TRIES times) int tries = 0; do { #pragma warning disable 612, 618 parent = symbolicExpressionTree.Root.IterateNodesPrefix().Skip(1).Where(n => n.SubtreeCount > 0).SelectRandom(random); #pragma warning restore 612, 618 childIndex = random.Next(parent.SubtreeCount); child = parent.GetSubtree(childIndex); int existingSubtreeCount = child.SubtreeCount; allowedSymbols.Clear(); foreach (var symbol in parent.Grammar.GetAllowedChildSymbols(parent.Symbol, childIndex)) { // check basic properties that the new symbol must have if (symbol.Name != child.Symbol.Name && symbol.InitialFrequency > 0 && existingSubtreeCount <= parent.Grammar.GetMinimumSubtreeCount(symbol) && existingSubtreeCount >= parent.Grammar.GetMaximumSubtreeCount(symbol)) { // check that all existing subtrees are also allowed for the new symbol bool allExistingSubtreesAllowed = true; for (int existingSubtreeIndex = 0; existingSubtreeIndex < existingSubtreeCount && allExistingSubtreesAllowed; existingSubtreeIndex++) { var existingSubtree = child.GetSubtree(existingSubtreeIndex); allExistingSubtreesAllowed &= parent.Grammar.IsAllowedChildSymbol(symbol, existingSubtree.Symbol, existingSubtreeIndex); } if (allExistingSubtreesAllowed) { allowedSymbols.Add(symbol); } } } tries++; } while (tries < MAX_TRIES && allowedSymbols.Count == 0); if (tries < MAX_TRIES) { var weights = allowedSymbols.Select(s => s.InitialFrequency).ToList(); #pragma warning disable 612, 618 var newSymbol = allowedSymbols.SelectRandom(weights, random); #pragma warning restore 612, 618 // replace the old node with the new node var newNode = newSymbol.CreateTreeNode(); if (newNode is TreeModelTreeNode treeNode) { int p = random.Next(map.Count); if (child is TreeModelTreeNode chNode) { p = chNode.ClusterNumer; } treeNode.TreeNumber = map[p].SampleRandom(random).Value; treeNode.Tree = (ISymbolicExpressionTree)modelSet[treeNode.TreeNumber].Clone(); treeNode.ClusterNumer = p; treeNode.SetLocalParameters(random, 0.5); } else if (newNode.HasLocalParameters) newNode.ResetLocalParameters(random); foreach (var subtree in child.Subtrees) newNode.AddSubtree(subtree); parent.RemoveSubtree(childIndex); parent.InsertSubtree(childIndex, newNode); } } } }