/*
* Copyright 2007-2008 Lawrence Beadle & Tom Castle
* Licensed under GNU General Public License
*
* This file is part of Epoch X - (The Genetic Programming Analysis Software)
*
* Epoch X 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.
*
* Epoch X 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 Epoch X. If not, see <http://www.gnu.org/licenses/>.
*/
package org.epochx.semantics;
import net.sf.javabdd.BDD;
import net.sf.javabdd.BDDFactory;
import java.util.*;
import org.epochx.core.Model;
import org.epochx.epox.*;
import org.epochx.epox.bool.*;
import org.epochx.gp.model.GPModel;
import org.epochx.gp.representation.GPCandidateProgram;
import org.epochx.representation.CandidateProgram;
/**
* The Boolean Semantic Module provides semantic functionality
* for problems in the Boolean domain including reduction to
* canonical representations of behaviour
*/
public class BooleanSemanticModule implements SemanticModule {
private BDDFactory bddLink;
private List<BDD> bddList;
private List<BooleanVariable> terminals;
private Model model;
private String environment;
/**
* Constructor for Boolean Semantic Module
* @param list List of terminal nodes
* @param model The GPModel object
*/
public BooleanSemanticModule(List<BooleanVariable> list, Model model, String environment) {
this.terminals = list;
this.model = model;
this.environment = environment;
}
public void start() {
// set up BDD analyser
this.bddLink = BDDFactory.init("cudd", (terminals.size()*500), (terminals.size()*500));
// create all possible base variables
this.bddList = new ArrayList<BDD>();
for(int i = 0; i<terminals.size(); i++) {
bddList.add(bddLink.ithVar(i));
}
}
public void stop() {
// close down bdd link
bddLink.done();
}
/* (non-Javadoc)
* @see com.epochx.semantics.SemanticModule#codeToBehaviour(com.epochx.core.representation.CandidateProgram)
*/
@Override
public BooleanRepresentation codeToBehaviour(CandidateProgram program) {
// pull root node out of candidate program
SemanticCandidateProgram prog1 = new SemanticCandidateProgram(program);
BooleanNode rootNode = (BooleanNode) prog1.getRootNode();
return this.calculateBooleanRepresentation(rootNode);
}
private BooleanRepresentation calculateBooleanRepresentation(BooleanNode rootNode) {
// break up nodes and call respective bits recursively
if(rootNode instanceof BooleanVariable) {
// A TERMINAL
int index = terminals.indexOf(rootNode);
return new BooleanRepresentation(bddList.get(index));
} else if(rootNode instanceof NotFunction) {
// NOT
// resolve child behaviour
BooleanRepresentation childBehaviour = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(0));
BDD childBDD = childBehaviour.getBDD();
BDD result = childBDD.not();
return new BooleanRepresentation(result);
} else if(rootNode instanceof AndFunction) {
// AND
// resolve child behaviour
BooleanRepresentation childBehaviour1 = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(0));
BooleanRepresentation childBehaviour2 = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(1));
BDD childBDD1 = childBehaviour1.getBDD();
BDD childBDD2 = childBehaviour2.getBDD();
BDD result = childBDD1.and(childBDD2);
return new BooleanRepresentation(result);
} else if(rootNode instanceof OrFunction) {
// OR
// resolve child behaviour
BooleanRepresentation childBehaviour1 = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(0));
BooleanRepresentation childBehaviour2 = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(1));
BDD childBDD1 = childBehaviour1.getBDD();
BDD childBDD2 = childBehaviour2.getBDD();
BDD result = childBDD1.or(childBDD2);
return new BooleanRepresentation(result);
} else if(rootNode instanceof IfFunction) {
// IF
// resolve child behaviour
BooleanRepresentation childBehaviour1 = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(0));
BooleanRepresentation childBehaviour2 = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(1));
BooleanRepresentation childBehaviour3 = this.calculateBooleanRepresentation((BooleanNode) rootNode.getChild(2));
BDD childBDD1 = childBehaviour1.getBDD();
BDD childBDD2 = childBehaviour2.getBDD();
BDD childBDD3 = childBehaviour3.getBDD();
BDD result = childBDD1.ite(childBDD2, childBDD3);
return new BooleanRepresentation(result);
}
// if it gets here without returning something is wrong - unrecognised node present
throw new IllegalArgumentException("BDD Resolution error - Unidentified Syntax Present");
}
/* (non-Javadoc)
* @see com.epochx.semantics.SemanticModule#behaviourToCode(com.epochx.semantics.Behaviour)
*/
@Override
public CandidateProgram behaviourToCode(Representation representation) {
// convert to boolean representation
BooleanRepresentation booleanRep = (BooleanRepresentation) representation;
BDD bddRep = booleanRep.getBDD();
BooleanNode rootNode = this.resolveTranslation(bddRep);
CandidateProgram result = null;
if(environment.equalsIgnoreCase("GP")) {
result = new GPCandidateProgram(rootNode, (GPModel) model);
} else if(environment.equalsIgnoreCase("GE")) {
// TODO construct GE program
} else if(environment.equalsIgnoreCase("GR")) {
// TODO construct GR program
}
return result;
}
private BooleanNode resolveTranslation(BDD topBDD) {
// check tautology
if(topBDD.isOne() || topBDD.isZero()) {
throw new IllegalArgumentException("CANNOT REVERSE TRANSLATE A CONSTANT");
}
// get the BDD children
BDD highChild = topBDD.high();
BDD lowChild = topBDD.low();
// work out what's what and return node structure
if((!highChild.isOne() && !highChild.isZero()) && (!lowChild.isOne() && !lowChild.isZero())) {
// IF statement
BooleanVariable tNode = (BooleanVariable) terminals.get(topBDD.var()).clone();
IfFunction thisIF = new IfFunction(tNode, this.resolveTranslation(highChild), this.resolveTranslation(lowChild));
return thisIF;
} else if((!highChild.isOne() && !highChild.isZero()) && lowChild.isZero()) {
// AND statement
BooleanVariable tNode = (BooleanVariable) terminals.get(topBDD.var()).clone();
AndFunction thisAND = new AndFunction(tNode, this.resolveTranslation(highChild));
return thisAND;
} else if(highChild.isOne() && (!lowChild.isOne() && !lowChild.isZero())) {
// OR statement
BooleanVariable tNode = (BooleanVariable) terminals.get(topBDD.var()).clone();
OrFunction thisOR = new OrFunction(tNode, this.resolveTranslation(lowChild));
return thisOR;
} else if(highChild.isZero() && lowChild.isOne()) {
// NOT statement
BooleanVariable tNode = (BooleanVariable) terminals.get(topBDD.var()).clone();
NotFunction thisNOT = new NotFunction(tNode);
return thisNOT;
} else if(highChild.isOne() && lowChild.isZero()) {
// Variable
BooleanVariable tNode = (BooleanVariable) terminals.get(topBDD.var()).clone();
BooleanVariable thisVar = tNode;
return thisVar;
} else if(highChild.isZero() && (!lowChild.isOne() && !lowChild.isZero())) {
// AND ( NOT...
BooleanVariable tNode = (BooleanVariable) terminals.get(topBDD.var()).clone();
NotFunction thisNOT = new NotFunction(tNode);
AndFunction thisAND = new AndFunction(thisNOT, this.resolveTranslation(lowChild));
return thisAND;
} else if((!highChild.isOne() && !highChild.isZero()) && lowChild.isOne()) {
// OR ( NOT...
BooleanVariable tNode = (BooleanVariable) terminals.get(topBDD.var()).clone();
NotFunction thisNOT = new NotFunction(tNode);
OrFunction thisOR = new OrFunction(thisNOT, this.resolveTranslation(highChild));
return thisOR;
}
// throw exception if it made it to here without returning
throw new IllegalArgumentException("Unidentified Syntax in Reverse Translation");
}
}