package com.plectix.simulator.staticanalysis.rulecompression;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.Map.Entry;
import com.plectix.simulator.staticanalysis.Agent;
import com.plectix.simulator.staticanalysis.LinkStatus;
import com.plectix.simulator.staticanalysis.Rule;
import com.plectix.simulator.staticanalysis.Site;
public class RootedRule {
private List<ShadowAgent> roots;
// actions for all agents
private final Map<Integer, List<String>> actionStringsByAgentIDInRuleHandSide;
private final Map<Integer, ShadowAgent> mapAfter;
private final Map<Integer, ShadowAgent> mapBefore;
// parent rule
private Rule rule;
/**
* clone RootedRule from RuleMaster
*
* @param mapBefore
* @param mapAfter
*/
public RootedRule(Map<Integer, ShadowAgent> mapBefore,
Map<Integer, ShadowAgent> mapAfter) {
actionStringsByAgentIDInRuleHandSide = new LinkedHashMap<Integer, List<String>>();
this.mapBefore = new LinkedHashMap<Integer, ShadowAgent>();
this.mapAfter = new LinkedHashMap<Integer, ShadowAgent>();
RuleCompressionUtils.shadowClone(mapBefore, this.mapBefore);
RuleCompressionUtils.shadowClone(mapAfter, this.mapAfter);
}
public void setRootsAndFullActionInfo(Set<Integer> numbers) {
roots = new LinkedList<ShadowAgent>();
for (Integer i : numbers) {
ShadowAgent agent = mapBefore.get(i);
if (agent == null) {
roots.add(mapAfter.get(i));
} else {
roots.add(agent);
}
}
rangeAgentsFromRoots();
fullAddActions();
fullModifyActions();
fullBreakActions();
fullBoundActions();
fullDeleteActions();
fullTestActions();
}
// ============================================================================================
// methods for find correspondence
/**
* find map : agents of this rule -> agents of argumentRule
*/
public Map<Integer, Integer> findCorrespondenceToRule(RootedRule r) {
Map<Integer, List<String>> secondRuleActions = r.getActions();
Map<Integer, Integer> correspondence = new LinkedHashMap<Integer, Integer>();
Set<Integer> used = new LinkedHashSet<Integer>();
for (Integer i : actionStringsByAgentIDInRuleHandSide.keySet()) {
Integer j = getSecondRuleAction(
actionStringsByAgentIDInRuleHandSide.get(i),
secondRuleActions,used);
if (j != null) {
correspondence.put(i, j);
used.add(j);
} else {
return null;
}
}
if (used.size() == secondRuleActions.keySet().size()) {
return expand(correspondence, r);
}
return null;
}
/**
* expand correspondence from action agents to all compatible agents
*
* @param correspondence
* @param r
* @return
*/
private Map<Integer, Integer> expand(Map<Integer, Integer> correspondence,
RootedRule r) {
Stack<Integer> search = new Stack<Integer>();
Set<Integer> used = new LinkedHashSet<Integer>();
search.addAll(correspondence.keySet());
while (!search.isEmpty()) {
Integer pop = search.pop();
if (used.contains(pop))
continue;
used.add(pop);
ShadowAgent popAgent = mapBefore.get(pop);
if (popAgent == null) {
popAgent = mapAfter.get(pop);
}
for (Site s : getNeighboorsSites(popAgent)) {
if (s.getLinkState().getStatusLink() == LinkStatus.FREE)
continue;
Agent linkedAgent = s.getLinkState().getConnectedSite()
.getParentAgent();
int idInRuleHandside = linkedAgent.getIdInRuleHandside();
Integer old = correspondence.get(idInRuleHandside);
Integer idAgentByConnectedSite = r.idAgentByConnectedSite(
correspondence.get(pop), s.getName());
if (old == null) {
ShadowAgent shadowAgent = r.getMapBefore().get(idAgentByConnectedSite);
if(shadowAgent==null){
shadowAgent = r.getMapAfter().get(idAgentByConnectedSite);
}
if(shadowAgent!=null
&& linkedAgent.getName().equals(shadowAgent.getName())){
correspondence.put(idInRuleHandside,
idAgentByConnectedSite);
}
} else {
if (idAgentByConnectedSite != null
&& !old.equals(idAgentByConnectedSite)) {
throw new RuntimeException("interanl error");
}
}
search.add(idInRuleHandside);
}
}
return correspondence;
}
Integer idAgentByConnectedSite(Integer idAgent, String siteName) {
ShadowAgent shadowAgent = mapBefore.get(idAgent);
if (shadowAgent == null) {
shadowAgent = mapAfter.get(idAgent);
if (shadowAgent == null) {
return null;
}
}
Site siteByName = shadowAgent.getSiteByName(siteName);
if (siteByName == null) {
return null;
}
Site connectedSite = siteByName.getLinkState().getConnectedSite();
if (connectedSite == null) {
return null;
}
return connectedSite.getParentAgent().getIdInRuleHandside();
}
/**
* return idInRule HandSide of agents with actions as list
*
* @param list
* of action-string
* @param secondRuleActions
* @param used
* @return
*/
private Integer getSecondRuleAction(List<String> list,
Map<Integer, List<String>> secondRuleActions, Set<Integer> used) {
for (Entry<Integer, List<String>> entry : secondRuleActions.entrySet()) {
if(used.contains(entry.getKey()))
continue;
if (RuleCompressionUtils.equiv(entry.getValue(), list)) {
return entry.getKey();
}
}
return null;
}
Set<Site> getNeighboorsSites(ShadowAgent agent) {
Set<Site> siteToNeighboors = new HashSet<Site>();
for (Site s : agent.getSites()) {
if (s.getLinkState().getStatusLink() == LinkStatus.BOUND) {
Site connectedSite = s.getLinkState().getConnectedSite();
if (connectedSite != null) {
siteToNeighboors.add(s);
}
}
}
return siteToNeighboors;
}
/**
* range tree of agents (roots of trees - roots)
*/
private void rangeAgentsFromRoots() {
Stack<ShadowAgent> markedAgents = new Stack<ShadowAgent>();
int number = 0;
for (ShadowAgent sa : mapBefore.values()) {
number++;
sa.setRange(-1);
}
for (ShadowAgent sa : mapAfter.values()) {
if (mapBefore.get(sa.getIdInRuleHandside()) == null) {
number++;
continue;
}
sa.setRange(-1);
}
for (ShadowAgent sa : roots) {
markedAgents.add(sa);
sa.setRange(0);
}
// number -= roots.size();
while (!markedAgents.isEmpty()) {
ShadowAgent popAgent = markedAgents.pop();
number--;
if (mapBefore.get(popAgent.getIdInRuleHandside()) == null) {
continue;
}
for (Site siteNeigh : getNeighboorsSites(popAgent)) {
ShadowAgent neigh = (ShadowAgent) siteNeigh.getLinkState()
.getConnectedSite().getParentAgent();
if (neigh.getRange() != -1) {
if (popAgent.getParentInTree() != null) {
throw new RuntimeException("cyclic rule!!");
}
popAgent.setSiteToParentInTree(siteNeigh);
continue;
}
neigh.setRange(popAgent.getRange() + 1);
markedAgents.push(neigh);
}
}
if (number != 0) {
throw new RuntimeException("less roots that it is needed");
}
}
// ============================================================
// getters
Map<Integer, List<String>> getActions() {
return actionStringsByAgentIDInRuleHandSide;
}
public Map<Integer, ShadowAgent> getMapBefore() {
return mapBefore;
}
public Map<Integer, ShadowAgent> getMapAfter() {
return mapAfter;
}
public void setRule(Rule rule) {
this.rule = rule;
}
public Rule getRule() {
return rule;
}
public List<Integer> getRoots() {
List<Integer> list = new LinkedList<Integer>();
for (ShadowAgent sa : roots) {
list.add(sa.getIdInRuleHandside());
}
return list;
}
// ===========================================================================
// strings and actions methods
private void fullTestActions() {
for (ShadowAgent sa : roots) {
if (sa.isActionAgent())
continue;
String action = "TEST : " + sa.getName() + "()";
putStringToActionList(sa.getIdInRuleHandside(), action);
}
}
private void fullBreakActions() {
for (ShadowAgent sa : mapBefore.values()) {
if (!sa.isActionAgent())
continue;
if (mapAfter.get(sa.getIdInRuleHandside()) == null) {
for (Site s : sa.getSites()) {
if (s.getLinkState().getStatusLink() == LinkStatus.BOUND) {
Site other = s.getLinkState().getConnectedSite();
putStringForBreakAction(sa, s, other);
}
}
} else {
for (Site s : sa.getSites()) {
if (s.getLinkState().getStatusLink() == LinkStatus.BOUND) {
Site other = s.getLinkState().getConnectedSite();
Site doubleSite = mapAfter
.get(sa.getIdInRuleHandside()).getSiteByName(
s.getName());
if (doubleSite.getLinkState().getStatusLink() == LinkStatus.FREE
|| (other != null && other.getParentAgent()
.getIdInRuleHandside() != doubleSite
.getLinkState().getConnectedSite()
.getParentAgent().getIdInRuleHandside())) {
putStringForBreakAction(sa, s, other);
}
}
}
}
}
}
private void putStringForBreakAction(ShadowAgent sa, Site s, Site other) {
int idInRuleHandside = sa.getIdInRuleHandside();
if (other == null
|| ((ShadowAgent) other.getParentAgent()).getRange() > sa
.getRange()) {
String action = "BREAK : " + sa.getName() + "(" + s.getName()
+ ") " + getActionString(sa);
putStringToActionList(idInRuleHandside, action);
} else {
if (((ShadowAgent) other.getParentAgent()).getRange() == sa
.getRange()) {
String action = "BREAK : "
+ sa.getName()
+ "("
+ s.getName()
+ ")"
+ getActionString(sa)
+ " BREAK : "
+ other.getParentAgent().getName()
+ "("
+ other.getName()
+ ")"
+ getActionString((ShadowAgent) (other.getParentAgent()));
putStringToActionList(idInRuleHandside, action);
}
}
}
private void putStringToActionList(int idInRuleHandside, String action) {
if (actionStringsByAgentIDInRuleHandSide.get(idInRuleHandside) == null) {
actionStringsByAgentIDInRuleHandSide.put(idInRuleHandside,
new LinkedList<String>());
}
actionStringsByAgentIDInRuleHandSide.get(idInRuleHandside).add(action);
}
private void fullBoundActions() {
for (ShadowAgent sa : mapBefore.values()) {
if (!sa.isActionAgent())
continue;
int idInRuleHandside = sa.getIdInRuleHandside();
if (mapAfter.get(idInRuleHandside) == null)
continue;
for (Site s : sa.getSites()) {
Site other = mapAfter.get(idInRuleHandside).getSiteByName(
s.getName());
if (other.getLinkState().getStatusLink() == LinkStatus.FREE
|| other.getLinkState().getConnectedSite() == null)
continue;
Agent boundedAgent = other.getLinkState().getConnectedSite()
.getParentAgent();
if (mapBefore.get(boundedAgent.getIdInRuleHandside()) == null) {
// see next "for" for this case
continue;
}
if (s.getLinkState().getStatusLink() == LinkStatus.FREE
|| s.getLinkState().getConnectedSite() == null
|| s.getLinkState().getConnectedSite().getParentAgent()
.getIdInRuleHandside() != boundedAgent
.getIdInRuleHandside()) {
putStringToBoundAction(sa, s, other, mapBefore
.get(boundedAgent.getIdInRuleHandside()));
}
}
}
for (ShadowAgent sa : mapAfter.values()) {
if (!sa.isActionAgent())
continue;
if (mapBefore.get(sa.getIdInRuleHandside()) != null) {
throw new RuntimeException();
}
for (Site s : sa.getSites()) {
if (s.getLinkState().getStatusLink() == LinkStatus.BOUND) {
Site other = s.getLinkState().getConnectedSite();
if (mapBefore.get(other.getParentAgent()
.getIdInRuleHandside()) == null) {
putStringToBoundAction(sa, s, other, other
.getParentAgent());
} else {
putStringToBoundAction(sa, s, other, mapBefore
.get(other.getParentAgent()
.getIdInRuleHandside()));
}
}
}
}
}
private void putStringToBoundAction(ShadowAgent sa, Site s, Site other,
Agent boundedAgent) {
String action = "BOUND : " + sa.getName() + "(" + s.getName() + ")"
+ getActionString(sa) + "BOUND : " + boundedAgent.getName()
+ "(" + other.getName() + ")"
+ getActionString((ShadowAgent) boundedAgent);
int idInRuleHandside = sa.getIdInRuleHandside();
putStringToActionList(idInRuleHandside, action);
}
private void fullModifyActions() {
for (ShadowAgent sa : mapBefore.values()) {
if (!sa.isActionAgent())
continue;
if (mapAfter.get(sa.getIdInRuleHandside()) == null)
continue;
int idInRuleHandside = sa.getIdInRuleHandside();
for (Site other : mapAfter.get(idInRuleHandside).getSites()) {
Site site = mapBefore.get(idInRuleHandside).getSiteByName(
other.getName());
if (!other.getInternalState().equalz(site.getInternalState())) {
String action = "MODIFY : " + sa.getName() + "("
+ other.getName() + ") " + "internalState : "
+ other.getInternalState().getName()
+ getActionString(sa);
putStringToActionList(idInRuleHandside, action);
}
}
}
}
private void fullDeleteActions() {
for (ShadowAgent sa : mapBefore.values()) {
if (!sa.isActionAgent())
continue;
int idInRuleHandside = sa.getIdInRuleHandside();
if (mapAfter.get(idInRuleHandside) != null)
continue;
String action = "DELETE : " + sa.getName() + getActionString(sa);
putStringToActionList(idInRuleHandside, action);
}
}
private void fullAddActions() {
for (ShadowAgent sa : mapAfter.values()) {
if (!sa.isActionAgent())
continue;
int idInRuleHandside = sa.getIdInRuleHandside();
if (mapBefore.get(idInRuleHandside) != null) {
throw new RuntimeException();
}
String action = "ADD : " + sa.toString();
putStringToActionList(idInRuleHandside, action);
}
}
private String getActionString(ShadowAgent sa) {
StringBuffer path = new StringBuffer(" path = ");
ShadowAgent runner = sa;
while (runner.getParentInTree() != null) {
Site siteToParentInTree = runner.getParentInTree();
path.append(siteToParentInTree.getName() + ",");
path.append(siteToParentInTree.getLinkState().getConnectedSite()
.getName() + ",");
path.append(siteToParentInTree.getLinkState().getConnectedSite()
.getParentAgent().getName());
runner = (ShadowAgent) siteToParentInTree.getLinkState()
.getConnectedSite().getParentAgent();
}
return path.toString();
}
public Collection<String> getActionsString() {
Collection<String> strings = new LinkedList<String>();
for (Integer i : actionStringsByAgentIDInRuleHandSide.keySet()) {
strings.addAll(actionStringsByAgentIDInRuleHandSide.get(i));
}
return strings;
}
}