Newer
Older
abgabensammlungSS15 / ea / ub8 / framework / gp / GPTree.java
@MaxXximus92 MaxXximus92 on 22 Jun 2015 10 KB ea8 scheiss code
package gp;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * A Generic GP tree implementation.
 * 
 * @author mkron
 *
 */
public abstract class GPTree {
	public static int MODE_FULL = 0;
	public static int MODE_GROW = 1;

	public Random ran = new Random();
	// schonmal was von Javadoc für public Felder gehört?? Ihr könnt doch
	// Schnittstellen nicht unkommentiert lassen.
	public int arity; // Stelligkeit des Knotens aha!
	protected int type; // Knotentyp . Schon mal was von Enums gehört...
	public int height; // Hoehe des Baumes
	public int nodeCount; // Knotenanzahl in diesem Baum
	public GPTree up, left, right; // Zeiger auf Eltern- und Unterknoten

	/**
	 * Constructor with tree initialization.
	 * 
	 * @param rand
	 * @param parent
	 * @param h
	 *            maximum height of the tree
	 * @param mode
	 *            0 is "full", 1 is "grow"
	 */
	public GPTree(GPTree parent, int h, int mode) {
		initRandomTree(parent, h, mode);
		if (!this.isValid()) {
			System.err.println("Error, invalid initialization!");
		}
	}

	/**
	 * Copy constructor
	 * 
	 * @param tree
	 *            the other tree
	 */
	public GPTree(GPTree tree) {
		/*
		 * Dieser Konstruktor erzeugt mit Hilfe von copyTree() eine tiefe Kopie
		 * des Baumes tree.
		 */
		if (!tree.isValid()) {
			throw new RuntimeException("not valid tree to copy");
		}
		this.arity = tree.arity;
		this.type = tree.type;
		this.height = tree.height;
		this.nodeCount = tree.nodeCount;
		this.up = tree.up;
		if (tree.left != null) {
			left = copyTree(tree.left);
			left.up = this;
		}
		if (tree.right != null) {
			right = copyTree(tree.right);
			right.up = this;
		}
		if (!this.isValid()) {
			throw new RuntimeException("after copy no valid tree");
		}
	}

	/**
	 * Random tree initialization.
	 * 
	 * @param parent
	 * @param maxH
	 *            maximum height of the new tree
	 * @param mode
	 *            0 is "full", 1 is "grow"
	 */
	public void initRandomTree(GPTree parent, int maxH, int mode) {
		/*
		 * Erzeugen Sie mit Hilfe von makeRandomSubtree() einen zufaelligen
		 * Baum. Verwenden Sie nicht direkt rekursiv den Konstruktor von GPTree,
		 * da sonst abgeleitete Typen mit dem Typ GPTree vermischt werden kann.
		 */
		// :-D :-D whooo das kommentar ist der hammer, da hat einer Vererbung
		// und Typen einfach nicht verstanden

		this.up = parent;
		makeRandomSubtree(maxH, mode);

	}

	private int getFunctionCount() {
		return getTermCount() + getUnaryCount() + getBinaryCount();
	}

	// ************* abstract methods
	// these two are abstract so that the subtypes can return the right type
	// they should again use GPTree's (copy) constructor!

	// na wie wärs den mit Javadoc ???
	public abstract GPTree makeRandomSubtree(int h, int mode);

	public abstract GPTree copyTree(GPTree tree);

	public abstract double evalTreeAt(Object o);

	public abstract int getTermCount(); // return number of terminals

	public abstract int getUnaryCount(); // return number of unary functions //
											// Toller Javadoc, so als
											// Kommentar...

	public abstract int getBinaryCount(); // return number of binary functions

	public abstract String getTermSymbol(int i); // return String for a terminal

	public abstract String getUnarySymbol(int i); // return String for a unary
													// function

	public abstract String getBinarySymbol(int i); // return String for a binary
													// function

	// ************* abstract methods end

	@Override
	public String toString() {
		/*
		 * Stellt den Baum durch eine Zeichenkette dar.
		 */
		switch (arity) {
		case 0:
			return getTermSymbol(type);
		case 1:
			return getUnarySymbol(type) + "(" + left.toString() + ")";
		case 2:
			return getBinarySymbol(type) + "(" + left.toString() + ","
					+ right.toString() + ")";
		}
		System.err.println("Invalid arity in GPTree!"); // Exceptions ? **
		return "";
	}

	// Hilfsfunktion zum Testen des Baumes auf Konsistenz
	private boolean isValid() {
		if (getFunctionCount() == 0) {
			return true; // assume correctness for an empty function set
		}
		switch (arity) {
		case 0:
			boolean a = ((left == null) && (right == null) && (height == 0) && (nodeCount == 1));
			if (!a) {
				System.out.println(a + "case 0");
				System.out.println(left);
				System.out.println(right);
				System.out.println(height);
				System.out.println(nodeCount);
				System.out.println("_________");
			}
			return a;
		case 1:
			boolean b = ((left != null)
					&& (right == null)
					&& (height == (left.height + 1))
					/* && (nodeCount == (left.nodeCount + 1)) */&& left
							.isValid() && (left.up == this));
			if (!b) {
				System.out.println(b + "case1");
				System.out.println("left" + left);
				System.out.println("right " + right);
				System.out
						.println("height " + height + " " + (left.height + 1));
				System.out.println("nodecount " + nodeCount + " "
						+ (left.nodeCount + 1));
				System.out.println("parent " + (left.up == this));
				System.out.println("_________");
			}
			return b;
		case 2:
			boolean c = ((left != null) && (right != null)
					&& (height == (Math.max(left.height, right.height) + 1))
					/* && (nodeCount == (left.nodeCount + right.nodeCount + 1)) */
					&& left.isValid() && right.isValid() && (left.up == this) && (right.up == this));
			if (!c) {
				System.out.println(c + "case2");
				System.out.println("left" + left);
				System.out.println("right " + right);
				System.out.println("height " + height + " "
						+ (Math.max(left.height, right.height) + 1));
				System.out.println("nodecount " + nodeCount + " "
						+ (left.nodeCount + right.nodeCount + 1));
				System.out.println("parent " + (left.up == this));
				System.out.println("_________");
			}
			return c;
		}
		return false;
	}

	/**
	 * Perform a GP crossover between two binary trees.
	 * 
	 * @param otherTree
	 *            the crossover partner
	 * @param h
	 *            the maximal height
	 */
	public void crossover(GPTree otherTree, int h) {
		/*
		 * Crossover zwischen den Baeumen this und tree wird ausgefuehrt.
		 * 
		 * Hinweis: wählen Sie zuerst zwei zufällige Teilbäume von this und
		 * otherTree. Dabei kann eine Vorstellung der Numerierung der
		 * Unterknoten helfen.
		 * 
		 * ist die maximale höhe der teilbäume gemeint? nichtmal gescheite
		 * javadoc gibts..
		 */

		if (!this.isValid()) {

			throw new RuntimeException("  this  not valid before crossover");
		}
		if (!otherTree.isValid()) {

			throw new RuntimeException("  othertree not valid before crossover");
		}

		List<GPTree> thisTrees = new ArrayList<GPTree>();
		List<GPTree> otherTrees = new ArrayList<GPTree>();
		getAllTreesSameOrLower(this, h, thisTrees);
		GPTree ts = null;
		GPTree os = null;
		if ((thisTrees.size() > 0)) {
			ts = thisTrees.get(ran.nextInt(thisTrees.size()));
		} else {
			return;
		}
		getAllTreesSameHight(otherTree, ts.height, otherTrees);
		if ((otherTrees.size() > 0)) {
			os = otherTrees.get(ran.nextInt(otherTrees.size()));
		} else {
			return;
		}
		if (os.up != null) {
			os.up.nodeCount -= os.nodeCount;
			os.up.nodeCount += ts.nodeCount;

			if (os.up.left.equals(os)) {
				os.up.left = ts;
			} else {
				os.up.right = ts;
			}
		}
		if (ts.up != null) {
			ts.up.nodeCount -= ts.nodeCount;
			ts.up.nodeCount += os.nodeCount; // todo notecount der eltern
												// anpassen --> das wird jetzt
												// echt zu viel code für die
												// paar punkte . Wir ignorieren
												// jetzt einfach den nodecount
												// bei der prüfung braucht man
												// eh nie
			if (ts.up.left.equals(ts)) {
				ts.up.left = os;
			} else {
				ts.up.right = os;
			}
		}
		GPTree op = os.up;
		os.up = ts.up;
		ts.up = op;
		if (!this.isValid()) {
			throw new RuntimeException("this is not valid after crossover");
		}
		if (!otherTree.isValid()) {
			throw new RuntimeException(
					"other tree is not valid after crossover");
		}

	}

	private void getAllTreesSameOrLower(GPTree start, int h, List<GPTree> result) {
		if (start.height >= 0) {
			if (start.height <= h) {
				result.add(start);
			}
			if (start.left != null) {
				getAllTreesSameOrLower(start.left, h, result);
			}
			if (start.right != null) {
				getAllTreesSameOrLower(start.right, h, result);
			}
		}
	};

	private void getAllTreesSameHight(GPTree start, int h, List<GPTree> result) {
		if (start.height >= h) {
			if (start.height == h) {
				result.add(start);
				return;
			}
			if (start.left != null) {
				getAllTreesSameHight(start.left, h, result);
			}
			if (start.right != null) {
				getAllTreesSameHight(start.right, h, result);
			}
		}
	};

	/**
	 * @param pMut
	 *            propability of mutation
	 * @param h
	 *            hight of the random subtree
	 * @param mode
	 *            0 is "full", 1 is "grow"
	 */
	public void mutate(double pMut, int h, int mode) {
		/*
		 * Der Baum wird mit einer Wahrscheinlichkeit von pMut mutiert und an
		 * einer zufaelligen Stelle durch einen zufaelligen Baum ersetzt.
		 */

		// Wie ist das zu verstehen? eine zufällige Stelle dieses Teilbaums?

		if (ran.nextDouble() <= pMut) {
			GPTree sub = null;
			GPTree ne = null;
			List<GPTree> treesOfSameHight = new ArrayList<GPTree>();
			getAllTreesSameHight(this, h, treesOfSameHight);
			if (treesOfSameHight.size() <= 0) {
				return;
			}
			sub = treesOfSameHight.get(ran.nextInt(treesOfSameHight.size()));
			ne = makeRandomSubtree(h, mode); // es wird immer nur ein Baum mit
												// wieder der gleichen höhe
												// erstellt wie der vorherige
			// Hier funktioniert unser code nicht da makeRandom subtree nur this
			// ändert und wir ja hier nicht auf subtypen casten können.
			// So und hier geben wir es auf die Aufgabe zu lösen, mit der
			// Hoffnung dass ihr uns nie wieder so schlecht kommentierten und so
			// häufig gegen Java-Spezifikationen verstoßenden Code gebt wie
			// diesen.

			ne.up = sub.up;
			if (ne.up != null) {
				sub.up.nodeCount -= sub.nodeCount;
				sub.up.nodeCount += ne.nodeCount;
				if (sub.up.left.equals(sub)) {
					sub.up.left = ne;
				} else {
					sub.up.right = ne;
				}
				sub.up = null;
			}

		}
		if (!this.isValid()) {
			System.err.println(this.toString() + "   not valid mutation");
			throw new RuntimeException("");
		}
	}

}