001 package com.hammurapi.reasoning.impl;
002
003 import java.util.ArrayList;
004 import java.util.List;
005 import java.util.Map;
006
007 import org.eclipse.emf.common.util.TreeIterator;
008 import org.eclipse.emf.ecore.EObject;
009
010 import com.hammurapi.flow.Flow;
011 import com.hammurapi.flow.Node;
012 import com.hammurapi.flow.Pin;
013 import com.hammurapi.flow.Transition;
014 import com.hammurapi.flow.runtime.impl.PassThroughTransition;
015
016 /**
017 * Optimizes flow by finding equal conditions emanating from
018 * the same pin and merging them.
019 * @author Pavel Vlasov
020 *
021 */
022 public class ConditionSharingOptimizer implements RuleSetFlowOptimizer {
023
024 // TODO - Copy connection keys during optimization.
025
026 /*
027 * Algorithm:
028 * 1. Iterate over pins
029 * 2. For a pin iterate over all permutations of two outbound transitions.
030 * 3. If transitions are passthrough or mapping, and the nodes on the other ends are conditional, check two nodes for equality.
031 * 4. If nodes are equal or mappingly equal, check that all inbound transitions can be re-connected from one node's pins to the other's pins.
032 * 5. Reconnect transitions, change pass-through to mapping or change mapping where required.
033 */
034
035 @Override
036 public void optimize(Flow ruleSetFlow) {
037 boolean optimized;
038 Z: do {
039 optimized = false;
040 TreeIterator<EObject> rcit = ruleSetFlow.eAllContents();
041 N: while (rcit.hasNext()) {
042 EObject next = rcit.next();
043 if (next instanceof Pin) {
044 Pin pin = (Pin) next;
045 Transition[] outputs = pin.getOutput().toArray(new Transition[pin.getOutput().size()]);
046 /* For every two outbound transitions from the pin we check if the transitions
047 * are pass-through
048 */
049 for (int idx1=0; idx1<outputs.length-1; ++idx1) {
050 for (int idx2=idx1+1; idx2<outputs.length; ++idx2) {
051 if (isPassThrhoughOrMapping(outputs[idx1]) && isPassThrhoughOrMapping(outputs[idx2])) {
052 Pin pin1 = outputs[idx1].getToPin();
053 Pin pin2 = outputs[idx2].getToPin();
054 /*
055 * If target pins belong to condition nodes
056 */
057 if (ConditionNode.class.equals(pin1.getNode().getType()) && ConditionNode.class.equals(pin2.getNode().getType())) {
058 /* List of parameter mappings with which conditions are equal. Maps parameters of the second node to
059 * parameters of the first node. */
060 List<Map<Integer, Integer>> paramMaps = new ArrayList<Map<Integer, Integer>>();
061 if (equal(pin1.getNode(), pin2.getNode(), paramMaps)) {
062 throw new UnsupportedOperationException();
063 }
064 }
065 }
066 }
067 }
068
069 }
070 }
071 } while (optimized);
072 }
073
074 private boolean sameName(String name, String name2) {
075 return name==null ? name2==null : name.equals(name2);
076 }
077
078 /**
079 * Compares conditions.
080 * @param name
081 * @param node
082 * @return
083 */
084 private boolean equal(Node node1, Node node2, List<Map<Integer,Integer>> paramMaps) {
085 // TODO Auto-generated method stub
086 return false;
087 }
088
089 private boolean isPassThrhoughOrMapping(Transition transition) {
090 return PassThroughTransition.class.getName().equals(transition.getType()) || MappingTransition.class.getName().equals(transition.getType());
091 }
092
093 /**
094 * This optimization shall be executed after elimination
095 * of unnecessary pass-through nodes and transitions.
096 */
097 @Override
098 public int getOrder() {
099 return 10;
100 }
101
102 }