package statechart.evolve;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import statechart.Model;
import statechart.Node;
import statechart.StatechartFactory;
import statechart.Transition;
public class Mutate {
//////These are parameters that can be changed by the user. Ideally they should go in a resource file!//////
// list of attributes that could be randomly selected
public static enum Attribute {
TE, TYPE, ACTIVITY
}
// list of actions that mutate could perform
public static enum Action {
ADD, REMOVE, EXPAND, NOTHING
}
// list of TE used for returning a random TE
// caution: if you add a TE add also its opposite to the second array
public static final String[] TEXPS = {"OtherSameTeamPlayerApproachesBall == true",
"BallFound == true",
"BallDistanceX <= 0.3 && abs(BallDistanceY) <= 0.1)",
"BallBearing >= 0",
"PlayerPlaying == true"};
public static final String[] TEXPS_OPPOSITE = {"OtherSameTeamPlayerApproachesBall == false",
"BallFound == false",
"BallDistanceX > 0.3 && abs(BallDistanceY) > 0.1)",
"BallBearing < 0",
"PlayerPlaying == false"};
// list of activities used for returning a random node activity
public static final String[] ACTIVITIES = {"PassBallLeftKick",
"PassBallRightKick",
"ShootToGoalLeftKick",
"ShootToGoalRightKick",
"ScanBall",
"FollowBall",
"ApproachBall"};
// list of labels used for returning a random node label
public static final String[] TYPES = {"BASIC", "CONDITION"};
public static int NrTemplates = 8;
public static int MaxNodesTemp4 = 5;
public static int MaxNodesTemp1 = 5;
public static int MaxNodesTemp8 = 5;
public static int MaxNodesTemp7 = 5;
///////////////////////////////////////////////////////////////////////////////////////////////////////
// collect all the nodes of the branch below the selected node (also remove transitions)
public static void collectNodes(Model model, Node node, List<Node> toBeDeleted) {
// if the node has no children
if (node.getChildren().size()==0) {
removeTransitions(model, node);
toBeDeleted.add(node);
} else { // if the node has children
for (Node children : node.getChildren()) {
removeTransitions(model, children);
toBeDeleted.add(children);
collectNodes(model, children, toBeDeleted);
}
}
}
// remove all the branch after the selected node
public static void removeNodes(Model model, List<Node> toBeDeleted){
for (Node node : toBeDeleted) {
boolean hasThisChild = false;//---spanoudo
if ((node.getFather_of() != null)
&& (node.getFather_of().getChildren().size() > 0)) {
for (Node node2 : node.getFather_of().getChildren()) {
if (node2.equals(node))
hasThisChild = true;
}
}
if (hasThisChild)
node.getFather_of().getChildren().remove(node);
node.setFather_of(null);
model.getNodes().remove(node);
}
}
// remove all transitions related to the deleted node
public static void removeTransitions(Model model, Node node) {
List<Transition> toBeDeleted = new LinkedList<Transition>();
for (Transition transition : model.getTransitions()) {
// transitions that have this node as source
if (transition.getSource().equals(node)) {
toBeDeleted.add(transition);
}
// transitions that have this node as target---spanoudo
if (transition.getTarget().equals(node)) {
toBeDeleted.add(transition);
}
}
for (Transition transition : toBeDeleted) {
model.getTransitions().remove(transition);
}
}
// add a node after the selected child
public static void addNode(Model model, Node node) {
// create a newNode and add it after node
Node newNode = newNode(model, node, "");
// connect the two nodes with a new transition and TE
List<Transition> nodeTransitions = new LinkedList<Transition>();
for (Transition transition : model.getTransitions()) {
if (transition.getSource().equals(node))
nodeTransitions.add(transition);
}
int selectTransition = randomGenerator(nodeTransitions.size());
Transition selectedTransition = nodeTransitions.get(selectTransition-1);
newTransition(model, newNode, selectedTransition.getTarget());
selectedTransition.setTarget(newNode);
// check the other nodes of the same level and define interactions with the newNode
// creating a List with all the nodes that could potentially be connected
List<Node> nodes = new LinkedList<Node>();
for (Node iterator : model.getNodes()) {
if (!iterator.getLabel().equalsIgnoreCase("0") &&
iterator.getFather_of().equals(newNode.getFather_of()) &&
!iterator.equals(newNode) &&
!iterator.getType().equalsIgnoreCase("START"))
nodes.add(iterator);
}
// if there are other nodes define randomly transitions and TE, else newNode is BASIC
if (nodes.size() >= 2) {
newNode.setType(randomAttribute(Attribute.TYPE));
int numberOfNewTransitions = randomGenerator(nodes.size());
for (int i = 1; i <= numberOfNewTransitions; i++) {
int selectNode = randomGenerator(nodes.size());
newTransition(model, newNode, nodes.get(selectNode));
// removing selectNode from the remaining List
nodes.remove(selectNode);
}
}
else {
newNode.setType("BASIC");
newNode.setActivity(randomAttribute(Attribute.ACTIVITY));
}
}
// creating a new node (given the father) and adding it to the model
public static Node newNode(Model model, Node father, String type) {
Node newNode = StatechartFactory.eINSTANCE.createNode();
newNode.setLabel(father.getLabel() + "." + (father.getChildren().size()+1));
newNode.setName(newNode.getLabel());
newNode.setFather_of(father);
newNode.setType(type);
father.getChildren().add(newNode);
return newNode;
}
// creating a new transition (given source and target) and adding it to the model
public static void newTransition(Model model, Node source, Node target) {
Transition newTransition = StatechartFactory.eINSTANCE.createTransition();
newTransition.setSource(source);
newTransition.setTarget(target);
newTransition.setTE(randomAttribute(Attribute.TE));
newTransition.setName(newTransition.getSource().getName() + "TO" + newTransition.getTarget().getName());
model.getTransitions().add(newTransition);
}
// select action for this node ADD, EXPAND, REMOVE, NOTHING
public static Action selectAction(Node node, int denominator) {
int action = randomGenerator(denominator);
if(node.getType().equalsIgnoreCase("BASIC")) {
switch (action) {
case 1: return Action.ADD; // probability: 1/denominator
case 2: return Action.REMOVE; // probability: 1/denominator
case 3: return Action.EXPAND; // probability: 1/denominator
default: return Action.NOTHING; // probability: rest
}
} else {
switch (action) {
case 1: return Action.ADD; // probability: 1/denominator
case 2: return Action.REMOVE; // probability: 1/denominator
default: return Action.NOTHING; // probability: rest
}
}
}
public static void expandNode(Model model, Node node) {
int chooseTemplate = randomGenerator(NrTemplates);
switch (chooseTemplate) {
case 1:
int n1 = randomGenerator(MaxNodesTemp4);
sequentialMatcher(model, node, n1);
break;
case 2:
int n2 = randomGenerator(MaxNodesTemp1);
orMatcher(model, node, n2);
break;
case 3:
int n3 = randomGenerator(MaxNodesTemp8);
parallelMatcher(model, node, n3);
break;
case 4:
complexOptionalTermMatcher(model, node);
break;
case 5:
zeroOrMoreTimesTermMatcher(model, node);
break;
case 6:
foreverTermMatcher(model, node);
break;
case 7:
oneOrMoreTimesTermMatcher(model, node);
break;
case 8:
int n4 = randomGenerator(MaxNodesTemp7);
parallelManyTimesTermMatcher(model, node, n4);
break;
}
}
// generate random integer between 1 and bound
public static int randomGenerator(int bound) {
Random generator = new Random();
return generator.nextInt(bound)+1;
}
// return a random attribute
public static String randomAttribute(Attribute attribute) {
String[] randomAttribute = null;
switch (attribute) {
case TE:
// for now we just choose one random TE (no complex TE included)
int chooseArray = randomGenerator(2);
if (chooseArray == 1)
randomAttribute = TEXPS;
else
randomAttribute = TEXPS_OPPOSITE;
break;
case TYPE:
randomAttribute = TYPES;
break;
case ACTIVITY:
randomAttribute = ACTIVITIES;
break;
default:
System.out.println("Check the randomAttribute method!\n");
break;
}
int chooseAttrribute = randomGenerator(randomAttribute.length);
return randomAttribute[chooseAttrribute-1];
}
// PDF file: Template 4
public static void sequentialMatcher(Model model, Node father, int n) {
father.setType("OR");
//@SuppressWarnings("unused")
@SuppressWarnings("unused")
Node newNode1 = newNode(model, father, "START");
for (int k=1; k<=n; k++) {
Node newNode2 = newNode(model, father, "BASIC");
newTransition(model, getNodeByLabel(father, new String(father
.getLabel()
+ "." + k)), newNode2);
}
Node newNode3 = newNode(model, father, "END");
newTransition(model, getNodeByLabel(father, new String(father
.getLabel()
+ "." + (n+1))), newNode3);
}
// PDF file: Template 1
public static void orMatcher(Model model, Node father, int n) {
father.setType("OR");
Node newNode1 = newNode(model, father, "START");
Node newNode2 = newNode(model, father, "CONDITION");
newTransition(model, newNode1, newNode2);
for (int k=1; k<=n; k++) {
Node newNode3 = newNode(model, father, "BASIC");
newTransition(model, newNode2, newNode3);
}
Node newNode4 = newNode(model, father, "END");
for (int k=3; k<=n+2; k++) {
newTransition(model, getNodeByLabel(father, new String(father
.getLabel()
+ "." + k)), newNode4);
}
}
// PDF file: Template 8
public static void parallelMatcher(Model model, Node father, int n) {
father.setType("OR");
Node newNode1 = newNode(model, father, "START");
Node newNode2 = newNode(model, father, "AND");
newTransition(model, newNode1, newNode2);
Node newNode3 = newNode(model, father, "END");
newTransition(model, newNode2, newNode3);
for (int k=1; k<=n; k++) {
Node newNode_ORs = newNode(model, newNode2, "OR");
sequentialMatcher(model, newNode_ORs, 1);
}
}
// PDF file: Template 6
public static void complexOptionalTermMatcher(Model model, Node father) {
father.setType("OR");
Node newNode1 = newNode(model, father, "START");
Node newNode2 = newNode(model, father, "CONDITION");
Node newNode3 = newNode(model, father, "BASIC");
Node newNode4 = newNode(model, father, "END");
newTransition(model, newNode1, newNode2);
newTransition(model, newNode2, newNode3);
newTransition(model, newNode2, newNode4);
newTransition(model, newNode3, newNode4);
}
// PDF file: Template 2
public static void zeroOrMoreTimesTermMatcher(Model model, Node father) {
father.setType("OR");
Node newNode1 = newNode(model, father, "START");
Node newNode2 = newNode(model, father, "CONDITION");
Node newNode3 = newNode(model, father, "BASIC");
Node newNode4 = newNode(model, father, "END");
newTransition(model, newNode1, newNode2);
newTransition(model, newNode2, newNode3);
newTransition(model, newNode3, newNode3);
newTransition(model, newNode2, newNode4);
newTransition(model, newNode3, newNode4);
}
// PDF file: Template 3
public static void foreverTermMatcher(Model model, Node father) {
father.setType("OR");
Node newNode1 = newNode(model, father, "START");
Node newNode2 = newNode(model, father, "BASIC");
newTransition(model, newNode1, newNode2);
newTransition(model, newNode2, newNode2);
}
// PDF file: Template 5
public static void oneOrMoreTimesTermMatcher(Model model, Node father) {
father.setType("OR");
Node newNode1 = newNode(model, father, "START");
Node newNode2 = newNode(model, father, "BASIC");
Node newNode3 = newNode(model, father, "END");
newTransition(model, newNode1, newNode2);
newTransition(model, newNode2, newNode2);
newTransition(model, newNode2, newNode3);
}
// PDF file: Template 7
public static void parallelManyTimesTermMatcher(Model model, Node father, int n) {
father.setType("OR");
Node newNode1 = newNode(model, father, "START");
Node newNode2 = newNode(model, father, "AND");
newTransition(model, newNode1, newNode2);
for (int k=1; k<=n; k++) {
Node newNode_ORs = newNode(model, newNode2, "OR");
foreverTermMatcher(model, newNode_ORs);
}
}
// the two methods below are used for getNodeByLabel
public static Node getNodeByLabel(Node root, String label) {
if(root.getLabel().equals(label))
return root;
else
return DFSearch(root, label);
}
public static Node DFSearch(Node root, String label){
Iterator<Node> it = root.getChildren().iterator();
Node search = null;
while( it.hasNext()){
search = it.next();
if(search.getLabel().equals(label)){
return search;
}
else if(search.getChildren().size()>0){
Node newsearch = DFSearch(search, label);
if (newsearch!=null)
return newsearch;
}
}
return null;
}
// relabel the whole model
public static void performRelabelling(Model m){
Node node = StatechartFactory.eINSTANCE.createNode();
node = m.getNodes().get(0);
node.setLabel("0");
labelingChildren(m, node);
labelingTransitions(m);
}
// label the transitions of a model
// (method copied from Angeliki -- KSE/StateChartDesign.diagram/src/statechart/diagram/edit/commands/)
public static void labelingTransitions(Model m){
Transition t = StatechartFactory.eINSTANCE.createTransition();
for(int i=0; i<m.getTransitions().size(); i++){
t = m.getTransitions().get(i);
if(t.getSource().getName()!=null && t.getTarget().getName()!=null)
t.setName(t.getSource().getName()+ "_TO_" + t.getTarget().getName());
else
t.setName("transition_"+i);
m.getTransitions().set(i, t);
}
}
// label all the children of the root of a model
// (method copied from Angeliki -- KSE/StateChartDesign.diagram/src/statechart/diagram/edit/commands/)
public static void labelingChildren(Model m, Node parent){
int order = 1;
int i=0;
int start = -1;
int end = -1;
for( i=0; i<parent.getChildren().size(); i++){
if(parent.getChildren().get(i).getType().equals("START")){
start = i;
if(end!=-1)
break;
}
if(parent.getChildren().get(i).getType().equals("END")){
end = i;
if(start!=-1)
break;
}
}
if(end!=-1)
parent.getChildren().get(end).setLabel(parent.getLabel()+"."+parent.getChildren().size());
//search target nodes of transitions with start source
LinkedList<Integer> index = new LinkedList<Integer>();
for(int q=0; q<m.getTransitions().size(); q++){
if(m.getTransitions().get(q).getSource().getLabel().equals(parent.getChildren().get(start).getLabel()))
index.add(q);
}
//set proper label for start
parent.getChildren().get(start).setLabel(parent.getLabel()+"."+Integer.toString(order));
order++;
i = start;
boolean done = true;
for(int o =0; o<parent.getChildren().size(); o++){
if(!parent.getChildren().get(o).getLabel().contains(".")){
done = false;
System.out.println("false");
break;
}
}
if(done)
return;
LinkedList<Integer> newIndex = new LinkedList<Integer>();
LinkedList<Integer> nodes = new LinkedList<Integer>();
while(!done){
for (int u=0; u<index.size(); u++){
if( parent.getChildren().contains(((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget()) &&
!((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget().getLabel().contains(".")){
for(int q=0; q<m.getTransitions().size(); q++){
if(m.getTransitions().get(q).getSource().getLabel().equals(((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget().getLabel())){
newIndex.add(q);
nodes.add(parent.getChildren().indexOf(m.getTransitions().get(q).getTarget()));
}
}
parent.getChildren().get(parent.getChildren().indexOf(((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget())).setLabel(parent.getLabel()+"."+Integer.toString(order));
if(parent.getChildren().get(parent.getChildren().indexOf(((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget())).getName()==null ||
!parent.getChildren().get(parent.getChildren().indexOf(((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget())).getType().equals("BASIC"))
parent.getChildren().get(parent.getChildren().indexOf(((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget())).setName(parent.getChildren().get(parent.getChildren().indexOf(((Transition)m.getTransitions().get((Integer)index.get(u))).getTarget())).getLabel());
order++;
}
}
done = true;
for(int o =0; o<parent.getChildren().size(); o++){
if(!parent.getChildren().get(o).getLabel().contains(".")){
done = false;
System.out.println("false");
break;
}
}
index = newIndex;
if(!nodes.isEmpty()){
i = (Integer) nodes.remove(0);
}else
break;
}
for(int k =0; k<parent.getChildren().size(); k++){
if(!parent.getChildren().get(k).getChildren().isEmpty())
labelingChildren(m, parent.getChildren().get(k));
}
}
}// end Mutate