package search.fitnessfunctions.util;
import gpinterpreter.stack.StackInstruction;
import gpinterpreter.stack.StackInterpreter;
import gpinterpreter.vector.VecInstruction;
import gpinterpreter.vector.VecInterpreter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jgap.Gene;
import org.jgap.IChromosome;
import org.jgap.impl.IntegerGene;
import primitives.cluster.ClusterHead;
import primitives.cluster.ClusterNode;
import primitives.cluster.ClusterUtils;
import primitives.cluster.IClusterLevel;
import primitives.graph.Node;
import search.fitnessfunctions.TreeFitnessFunction;
import search.genes.BitFieldInstructionGene;
import search.genes.GeneType;
import search.genes.InstructionGene;
import search.genes.IntegerInstructionGene;
import search.genes.StackInstructionGene;
/**
*
* @author mat
*/
public abstract class TreeTranslator {
public static ClusterHead getTree(IChromosome in, ClusterHead originalTree) {
GeneType type = (GeneType) in.getApplicationData();
List<Gene> prog = new ArrayList<Gene>();
for(int i =0; i < in.size(); i++){
prog.add(in.getGene(i));
}
return getTree(prog,originalTree, type);
}
public static ClusterHead getTree(List<Gene> in, ClusterHead originalTree, GeneType type){
switch (type) {
case INTEGER:
case SYMBOL:
case BITFIELD:
return convertInstructionGene((List)in, originalTree);
case STACK:
return convertStackGene((List)in, originalTree);
case FLAT:
return convertFlatGene((List)in, originalTree);
case HCLUST:
return convertHClustGene((List) in, originalTree);
default:
throw new RuntimeException(String.format("Gene Type \"%s\" is not recognised.", type));
}
}
public static ClusterHead convertInstructionGene(List<InstructionGene> program, ClusterHead originalTree) {
VecInterpreter interp = new VecInterpreter(new ArrayList<VecInstruction>(), originalTree.deepCopy());
int size = originalTree.getSize();
VecInstruction inst = null;
for (int i = 0; i < program.size(); i++) {
Gene g = program.get(i);
if (g instanceof IntegerGene) {
IntegerGene ig = (IntegerGene) g;
inst = IntegerInstructionGene.getInstruction(ig.intValue(),
size);
} else if (g instanceof InstructionGene) {
inst = ((InstructionGene) g).getInstruction();
}
interp.execute(inst);
}
return interp.getTree();
}
public static ClusterHead convertStackGene(List<StackInstructionGene> program, ClusterHead originalTree){
List<StackInstruction> conv = new ArrayList<StackInstruction>();
for(int i= 0; i< program.size(); i++){
conv.add(program.get(i).getInstruction());
}
return convertStackInstruction(conv, originalTree);
}
public static ClusterHead convertStackInstruction(List<StackInstruction> program, ClusterHead originalTree) {
StackInterpreter interp = new StackInterpreter(program, originalTree.deepCopy());
return interp.run();
}
public static ClusterHead convertFlatGene(List<IntegerGene> assignments, ClusterHead originalTree) {
Map<Integer, Node> nodenumbers = new HashMap<Integer, Node>();
for (IClusterLevel n : originalTree.getChildren()) {
if (n.encapsulates()) {
for (int x : n.getIDs()) {
if (x > 0) { //children start at 1, clusterhead is always 0
for (Node node : n.getNodes()) {
nodenumbers.put(x, node);
}
}
}
}
}
ClusterHead ch = new ClusterHead();
Map<Integer, ClusterNode> parents = new HashMap<Integer, ClusterNode>();
Set<Node> nodes = originalTree.getNodes();
for (int i = 0; i < assignments.size(); i++) {
int parentNumber = assignments.get(i).intValue();
Node cur = nodenumbers.get(i + 1);
if (cur == null) {
throw new RuntimeException(String.format("ERROR: Missing node %d, known nodes: %s", i, nodenumbers.keySet()));
}
ClusterNode parent = parents.get(parentNumber);
if (parent == null) {
parent = new ClusterNode();
parent.setID(parentNumber);
ch.addChild(parent);
parents.put(parentNumber, parent);
}
parent.addNode(cur);
nodes.remove(cur);
}
if (!nodes.isEmpty()) {
throw new RuntimeException(String.format("%d nodes weren't added to the new tree: {1}, ", nodes.size(), nodes.toString()));
}
return ch;
}
public static ClusterHead convertInstructionGene(IChromosome in, ClusterHead originalTree) {
ArrayList<InstructionGene> prog = new ArrayList<InstructionGene>();
for (int i = 0; i < in.size(); i++) {
prog.add((InstructionGene) in.getGene(i));
}
return convertInstructionGene(prog, originalTree);
}
public static ClusterHead convertStackGene(IChromosome in, ClusterHead originalTree) {
ArrayList<StackInstruction> prog = new ArrayList<StackInstruction>();
for (int i = 0; i < in.size(); i++) {
prog.add(((StackInstructionGene) in.getGene(i)).getInstruction());
}
return convertStackInstruction(prog, originalTree);
}
public static ClusterHead convertFlatGene(IChromosome in, ClusterHead originalTree) {
ArrayList<IntegerGene> assignments = new ArrayList<IntegerGene>();
for (int i = 0; i < in.size(); i++) {
assignments.add((IntegerGene) in.getGene(i));
}
return convertFlatGene(assignments, originalTree);
}
private static ClusterHead convertHClust(List<Integer> assignments, ClusterHead originalTree){
Map<Integer, Node> nodenumbers = new HashMap<Integer, Node>();
for (IClusterLevel n : originalTree.getChildren()) {
if (n.encapsulates()) {
for (int x : n.getIDs()) {
if (x > 0) { //children start at 1, clusterhead is always 0
for (Node node : n.getNodes()) {
nodenumbers.put(x, node);
}
}
}
}
}
ClusterHead newTree = new ClusterHead();
Map<Integer,ClusterNode> treenodes = new HashMap<Integer,ClusterNode>();
treenodes.put(0,newTree);
//allocate each node to its parent:
for(int i = 0; i<originalTree.getNodes().size(); i++){
int parent = assignments.get(i);
ClusterNode parentNode = treenodes.get(parent);
if(parentNode == null){
parentNode = new ClusterNode();
treenodes.put(parent, parentNode);
}
parentNode.addNode(nodenumbers.get(i+1));
}
//state is now that there are loads of clusters with the children they need.
//build the tree:
int treeSize = originalTree.getNodes().size();
for(int i = 0; i<assignments.size() - treeSize; i++){
int parent = assignments.get(i + treeSize); //pull parent id for child i from the array.
if(parent == i+1){
//Logger.getLogger(TreeTranslator.class.getName()).log(Level.INFO, "Attempted to make a child a parent of itself {0} from {1}",new Object[]{parent,i});
parent = 0;
}
ClusterNode parentNode = treenodes.get(parent); //parent is whatever that value was
if(parentNode == null){
//add intermediate parent that didn't have any nodes in it:
parentNode = new ClusterNode();
treenodes.put(parent,parentNode);
}
ClusterNode childNode = treenodes.get(i + 1); //i starts 0..n-1, they're numbered 1..n (0 is always reserved for the child).
if(childNode == null){
childNode = new ClusterNode();
treenodes.put(i+1, childNode);
}
parentNode.addChild(childNode);
if(ClusterUtils.isCyclic(parentNode)){
parentNode.deleteChild(childNode);
//Logger.getLogger(TreeTranslator.class.getName()).log(Level.INFO, "{0} was cyclic so the child {1} was removed", new Object[]{parentNode, childNode});
}
}
Set<ClusterNode> orphans = new HashSet<ClusterNode>();
for(ClusterNode n : treenodes.values()){
if(n != newTree && ClusterUtils.findParent(n, newTree) == null){
orphans.add(n);
}
}
for (Iterator<ClusterNode> it = orphans.iterator(); it.hasNext();) {
ClusterNode clusterNode = it.next();
boolean remove = false;
for(ClusterNode cn : orphans){
if(cn != clusterNode && ClusterUtils.findParent(clusterNode, cn) != null){
//if the current clusterNode can be found in any of the "trees" of the orphans
//then it isn't an orphan proper, just an orphan of the main ClusterHead - we can
//fix this problem by adopting its parent, so we remove it from our fixups.
remove = true;
break;
}
}
if(remove) it.remove();
}
//orphans should now contain all clusters that need to be adopted:
for(ClusterNode cn : orphans){
if(ClusterUtils.isCyclic(cn)){
throw new RuntimeException("A cyclic orphan was detected.");
}
newTree.addChild(cn);
}
if(ClusterUtils.isCyclic(newTree)){
Logger.getLogger(TreeTranslator.class.getName()).log(Level.WARNING, "Cyclic tree detected!");
throw new RuntimeException("There was a cyclic tree so I stopped.");
}
//ClusterUtils.prettyPrintTree(newTree);
Set<Node> oNodes = originalTree.getNodes();
Set<Node> tNodes = newTree.getNodes();
if(!oNodes.containsAll(tNodes) || !tNodes.containsAll(oNodes)){
Logger.getLogger(TreeTranslator.class.getName()).log(Level.INFO, "Converting a HCLUST: not all nodes were copied, Have {0} nodes but needed {1}.", new Object[]{tNodes.size(), oNodes.size()});
oNodes.removeAll(tNodes);
Logger.getLogger(TreeTranslator.class.getName()).log(Level.INFO, "Missing nodes are: {0}", new Object[]{oNodes});
}
return newTree;
}
private static ClusterHead convertHClustGene(List<IntegerGene> assignments, ClusterHead originalTree) {
ArrayList<Integer> chromosome = new ArrayList<Integer>();
for(int i =0; i< assignments.size(); i++){
chromosome.add(assignments.get(i).intValue());
}
return convertHClust(chromosome, originalTree);
}
}