/// <summary> /// Clonar el nodo /// </summary> public object Clone() { TreeNode clone = new TreeNode(); clone.Gene = this.Gene.Clone(); // se clonan los hijos tambien if (this.Children != null) { clone.Children = new ArrayList(); // de cada hijo clonamos sus genes foreach (TreeNode node in Children) { clone.Children.Add(node.Clone()); } } return clone; }
/// <summary> /// Rutina helper para el operador de cruce /// Selecciona un nodo random de un arbol y lo intercambia con otro /// nodo random de otro arbol /// </summary> private TreeNode RandomSwap(TreeNode source) { TreeNode retNode = null; // swappeamos la raiz? if ((root.Children == null) || (rand.Next(maxLevel) == 0)) { // intercambiamos retNode = root; root = source; } else { TreeNode node = root; for (; ; ) { // se elije un hijo random int r = rand.Next(node.Gene.ArgumentsCount); TreeNode child = (TreeNode)node.Children[r]; // swappeamos el hijo if ((child.Children == null) || (rand.Next(maxLevel) == 0)) { // con el nodo del amigo retNode = child; node.Children[r] = source; break; } // seguimos recorriendo el arbol node = child; } } return retNode; }
/// <summary> /// Constructor de copia /// </summary> protected TreeIndividual(TreeIndividual source) { root = (TreeNode)source.root.Clone(); fitness = source.fitness; }
/// <summary> /// Poda el arbol, para que no se pase del nivel provisto /// </summary> private static void Trim(TreeNode node, int level) { // checkear si tiene hijos if (node.Children != null) { if (level == 0) { // se quitan todos node.Children = null; // se hace que el nodo sea hoja node.Gene.Generate(GeneType.Argument); } else { // recorriendo los hijos foreach (TreeNode n in node.Children) { Trim(n, level - 1); } } } }
/// <summary> /// Genera un subarbol del nivel especificado /// </summary> protected void Generate(TreeNode node, int level) { if (level == 0) { // si el nivel es 0, deberia ser un argumento, pues // una expresion no puede contener solo un operador node.Gene = root.Gene.CreateNew(GeneType.Argument); } else { // si level > 0, puede ser operador o variable node.Gene = root.Gene.CreateNew(); } // agregar hijos if (node.Gene.ArgumentsCount != 0) { node.Children = new ArrayList(); for (int i = 0; i < node.Gene.ArgumentsCount; i++) { // nuevo hijo TreeNode child = new TreeNode(); Generate(child, level - 1); // agregar el hijo node.Children.Add(child); } } }
/// <summary> /// Operador de mutacion /// </summary> public virtual void Mutate() { // nivel actual int currentLevel = 0; // nodo actual TreeNode node = root; for (; ; ) { // regenerar nodo si no tiene hijos if (node.Children == null) { if (currentLevel == maxLevel) { // si llegamos al maximo nivel, en las hojas // solo puede haber variables node.Gene.Generate(GeneType.Argument); } else { // no llegamos al maximo nivel, generar subarbol Generate(node, rand.Next(maxLevel - currentLevel)); } break; } // Si es un nodo operador, debemos elegir el punto de mutacion, // el nodo mismo o uno de sus hijos int r = rand.Next(node.Gene.ArgumentsCount + 1); if (r == node.Gene.ArgumentsCount) { // el nodo mismo se regenera node.Gene.Generate(); // chequeamos el tipo if (node.Gene.GeneType == GeneType.Argument) { node.Children = null; } else { // crear lista de hijos si no tiene if (node.Children == null) node.Children = node.Children = new ArrayList(); // nos fijamos si le faltan argumentos al operador, //en tal caso agregamos hijos if (node.Children.Count != node.Gene.ArgumentsCount) { if (node.Children.Count > node.Gene.ArgumentsCount) { // quitamos hijos de mas node.Children.RemoveRange(node.Gene.ArgumentsCount, node.Children.Count - node.Gene.ArgumentsCount); } else { // agregamos hijos faltantes for (int i = node.Children.Count; i < node.Gene.ArgumentsCount; i++) { TreeNode child = new TreeNode(); Generate(child, rand.Next(maxLevel - currentLevel)); node.Children.Add(child); } } } } break; } node = (TreeNode)node.Children[r]; currentLevel++; } }
/// <summary> /// Generar arbol aleatorio /// </summary> public virtual void Generate() { // se aleatoriza la raiz root.Gene.Generate(); // y se crean hijos if (root.Gene.ArgumentsCount != 0) { root.Children = new ArrayList(); for (int i = 0; i < root.Gene.ArgumentsCount; i++) { // nuevo hijo TreeNode child = new TreeNode(); Generate(child, rand.Next(maxInitialLevel)); // se agrega al nuevo nodito root.Children.Add(child); } } }
/// <summary> /// Operador de cruce /// </summary> public virtual void Crossover(IIndividual pair) { TreeIndividual p = (TreeIndividual)pair; if (p != null) { // necesitamos cruzar en la raiz? if ((root.Children == null) || (rand.Next(maxLevel) == 0)) { // le damos la raiz al individuo, y lo usamos parte // suya como nueva raiz (seria como un injerto) root = p.RandomSwap(root); } else { TreeNode node = root; for (; ; ) { // elegimos un hijo al azar int r = rand.Next(node.Gene.ArgumentsCount); TreeNode child = (TreeNode)node.Children[r]; // swappeamos en un nodo al azar if ((child.Children == null) || (rand.Next(maxLevel) == 0)) { // con el del individuo provisto node.Children[r] = p.RandomSwap(child); break; } // continuamos por el arbol node = child; } } // podamos un poco //TODO: Comentar??? Trim(root, maxLevel); Trim(p.root, maxLevel); } }