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 com.plectix.simulator.interfaces.ConnectedComponentInterface; import com.plectix.simulator.staticanalysis.Agent; import com.plectix.simulator.staticanalysis.ConnectedComponent; import com.plectix.simulator.staticanalysis.InternalState; import com.plectix.simulator.staticanalysis.Link; import com.plectix.simulator.staticanalysis.LinkRank; import com.plectix.simulator.staticanalysis.LinkStatus; import com.plectix.simulator.staticanalysis.Rule; import com.plectix.simulator.staticanalysis.Site; import com.plectix.simulator.staticanalysis.abstracting.AbstractAgent; import com.plectix.simulator.staticanalysis.abstracting.AbstractSite; import com.plectix.simulator.staticanalysis.localviews.LocalViewsMain; public class RootedRulesGroup { private Map<RootedRule, Map<Integer, Integer>> rulesAndGluingThem; private RootedRule headerRule; private RootedRule compressed; private LocalViewsMain localViews; private ShadowAgent obstruction; private Set<Site> problemSites; private Set<Site> noProblemSites; private List<Integer> neededAgents; private String obstructionSite; public RootedRulesGroup(RootedRule r) { headerRule = r; rulesAndGluingThem = new LinkedHashMap<RootedRule, Map<Integer, Integer>>(); } // algorithm part // ======================================================== public boolean tryAdd(RootedRule r) { Map<Integer, Integer> gluing = headerRule.findCorrespondenceToRule(r); if (gluing == null) { return false; } else { rulesAndGluingThem.put(r, gluing); return true; } } public void findCommonPart() { obstruction = null; problemSites = new LinkedHashSet<Site>(); if (rulesAndGluingThem.size() == 0) { return; } compressed = new RootedRule(headerRule.getMapBefore(), headerRule .getMapAfter()); compressed.setRule(null); neededAgents = new LinkedList<Integer>(); noProblemSites = new LinkedHashSet<Site>(); Stack<Integer> stack = new Stack<Integer>(); stack.addAll(headerRule.getRoots()); Set<Integer> studied = new HashSet<Integer>(); Map<Integer, ShadowAgent> compressedMapBefore = compressed .getMapBefore(); obstructionSite = null; while (!stack.isEmpty()) { Integer current = stack.pop(); studied.add(current); neededAgents.add(current); // rules have same actions therefore they have same add actions if (headerRule.getMapBefore().get(current) == null) continue; ShadowAgent compressedAgentBefore = compressedMapBefore .get(current); brushAgents(current, compressedAgentBefore); if (obstruction != null) { break; } for (Site s : compressedAgentBefore.getSites()) { Site connectedSite = s.getLinkState().getConnectedSite(); if (connectedSite != null) { int idInRuleHandside = connectedSite.getParentAgent() .getIdInRuleHandside(); if (!studied.contains(idInRuleHandside)) { stack.add(idInRuleHandside); } } } } if (obstruction == null) { examineProblemSites(); } } /** * examine problems with merge a(x!1),b(x!1) and a(x!1),c(x!1) to a(x!_) * * @return problemSites empty - not problem. not empty - there are problem */ void examineProblemSites() { for (Site s : noProblemSites) { problemSites.remove(s); } if (problemSites.isEmpty()) { return; } Stack<Site> stack = new Stack<Site>(); stack.addAll(problemSites); while (!stack.isEmpty()) { Site site = stack.pop(); for (Site connectedSite : probablyConnectedWith(site)) { if (!RuleCompressionUtils.uniqueConponent(new AbstractSite(connectedSite, new AbstractAgent(connectedSite .getParentAgent().getName())), localViews)) { // stack not empty! return; } } problemSites.remove(site); } return; } private Set<Site> probablyConnectedWith(Site pop) { Set<Site> answer = new LinkedHashSet<Site>(); Integer id = pop.getParentAgent().getIdInRuleHandside(); for (RootedRule r : rulesAndGluingThem.keySet()) { Integer idInRule = rulesAndGluingThem.get(r).get(id); ShadowAgent sa = r.getMapBefore().get(idInRule); Site siteInRule = sa.getSiteByName(pop.getName()); if (siteInRule != null) { Site connectedSite = siteInRule.getLinkState() .getConnectedSite(); if (siteInRule.getLinkState().getStatusLinkRank() == LinkRank.SEMI_LINK) { throw new RuntimeException( "this site must be removed from problemSites!"); } if (connectedSite != null) { answer.add(connectedSite); } } } return answer; } Rule buildCompressedRule() { QuantitativeCompressor q = new QuantitativeCompressor(localViews); if (rulesAndGluingThem.size() == 0) { q.compress(headerRule.getRule()); return q.getCompressedRule(); } if(compressed.getRule()!=null){ return compressed.getRule(); } List<ConnectedComponentInterface> listBefore = new LinkedList<ConnectedComponentInterface>(); List<ConnectedComponentInterface> listAfter = new LinkedList<ConnectedComponentInterface>(); Rule rule = headerRule.getRule(); if (rule.getLeftHandSide() != null) { for (ConnectedComponentInterface c : rule.getLeftHandSide()) { List<Agent> newLeftSide = new LinkedList<Agent>(); for (Agent agent : c.getAgents()) { int id = agent.getIdInRuleHandside(); if (neededAgents.contains(id)) { newLeftSide.add(compressed.getMapBefore().get(id)); } } if (!newLeftSide.isEmpty()) { sortBefore(newLeftSide); listBefore.add(new ConnectedComponent(newLeftSide)); } } } if (rule.getRightHandSide() != null) { for (ConnectedComponentInterface c : rule.getRightHandSide()) { List<Agent> newRightSide = new LinkedList<Agent>(); for (Agent agent : c.getAgents()) { int id = agent.getIdInRuleHandside(); if (neededAgents.contains(id)) { newRightSide.add(compressed.getMapAfter().get(id)); } } if (!newRightSide.isEmpty()) { sortAfter(newRightSide); listAfter.add(new ConnectedComponent(newRightSide)); } } } if (listBefore.isEmpty()) { listBefore.add(new ConnectedComponent()); } q.compress(new Rule(listBefore, listAfter, rule.getName() + "_compressedGroup", 1, 0, false)); compressed.setRule(q.getCompressedRule()); return q.getCompressedRule(); } /** * find common part of test information by this id. Write to second argument<br> * If we have a problem with reachability then we full field obstruction * * @param id * @param commonTestedInformation */ void brushAgents(Integer id, ShadowAgent commonTestedInformation) { List<AbstractAgent> masks = new LinkedList<AbstractAgent>(); for (RootedRule r : rulesAndGluingThem.keySet()) { // added agents cann't be brushed ShadowAgent shadowAgent = r.getMapBefore().get( rulesAndGluingThem.get(r).get(id)); if (shadowAgent == null) { continue; } Agent realAgent = shadowAgent.getRealAgent(); generalize(commonTestedInformation, realAgent); masks.add(new AbstractAgent(realAgent)); } masks.add(new AbstractAgent(headerRule.getMapBefore().get(id).getRealAgent())); String site = localViews.getObstructionSiteForCoherentAgentAndList( masks, new AbstractAgent(commonTestedInformation)); if (site != null) { obstruction = commonTestedInformation; obstructionSite = site; } } /** * different internal states ->set empty InternalState different link -> set * wildcard or semilink * * @param brushedAgent * @param realAgent */ void generalize(ShadowAgent brushedAgent, Agent realAgent) { for (Site realSite : realAgent.getSites()) { String siteName = realSite.getName(); Site site = brushedAgent.getSiteByName(siteName); if (site != null) { int idInRuleHandside = brushedAgent.getIdInRuleHandside(); ShadowAgent applying = compressed.getMapAfter().get(idInRuleHandside); Site applyingSite =null; if(applying!=null){ applyingSite = applying.getSiteByName(siteName); } if (site.getInternalState() != InternalState.EMPTY_STATE && realSite.getInternalState() != InternalState.EMPTY_STATE) { if (!site.getInternalState().equalz( realSite.getInternalState())) { site.setInternalState(InternalState.EMPTY_STATE); ShadowAgent shadowAgentAfter = headerRule.getMapAfter().get(idInRuleHandside); ShadowAgent shadowAgentBefore = headerRule.getMapBefore().get(idInRuleHandside); if(shadowAgentAfter!=null){ if(shadowAgentBefore.getSiteByName(siteName).getInternalState().equalz(shadowAgentAfter.getSiteByName(siteName).getInternalState())){ applyingSite.setInternalState(InternalState.EMPTY_STATE); } } } } if (site.getLinkState().getStatusLink() == LinkStatus.WILDCARD) { continue; } if (!site.getLinkState().equalz(realSite.getLinkState())) { if (site.getLinkState().getStatusLink() == LinkStatus.FREE || realSite.getLinkState().getStatusLink() == LinkStatus.FREE) { site.getLinkState().setWildLinkState(); applyingSite.getLinkState().setWildLinkState(); continue; } if (realSite.getLinkState().getStatusLinkRank() == LinkRank.SEMI_LINK) { noProblemSites.add(site); } else { problemSites.add(site); } site.getLinkState().setSemiLink(); ShadowAgent shadowAgentAfter = headerRule.getMapAfter().get(idInRuleHandside); ShadowAgent shadowAgentBefore = headerRule.getMapBefore().get(idInRuleHandside); if(shadowAgentAfter!=null){ if(shadowAgentBefore.getSiteByName(siteName).getLinkState().equalz(shadowAgentAfter.getSiteByName(siteName).getLinkState())){ applyingSite.getLinkState().setSemiLink(); } } } if(site.getInternalState().equalz(InternalState.EMPTY_STATE)&&site.getLinkState().getStatusLink()==LinkStatus.WILDCARD){ if(applying==null){ brushedAgent.removeSite(site.getName()); } else{ if(applyingSite.getInternalState().equalz(InternalState.EMPTY_STATE)&& applyingSite.getLinkState().getStatusLink()==LinkStatus.WILDCARD){ brushedAgent.removeSite(site.getName()); applying.removeSite(site.getName()); } } } } } } public boolean divide(Map<Rule, RootedRulesGroup> groups) { if (obstruction != null) { List<RootedRule> rules = featureDivider(obstructionSite, obstruction.getIdInRuleHandside()); RootedRulesGroup rg = getNewGroup(rules); rg.setViews(localViews); for (RootedRule rr : rules) { groups.put(rr.getRule(), rg); } return true; } else { if (!problemSites.isEmpty()) { Site s = problemSites.iterator().next(); List<RootedRule> rules = featureDivider(s.getName(), s .getParentAgent().getIdInRuleHandside()); RootedRulesGroup rg = getNewGroup(rules); rg.setViews(localViews); for (RootedRule rr : rules) { groups.put(rr.getRule(), rg); } return true; } return false; } } private List<RootedRule> featureDivider(String siteName, int idInRuleHandside) { Link linkState = headerRule.getMapBefore().get(idInRuleHandside) .getSiteByName(siteName).getLinkState(); List<RootedRule> secondListRule = new LinkedList<RootedRule>(); for (RootedRule rr : rulesAndGluingThem.keySet()) { Integer id = rulesAndGluingThem.get(rr).get(idInRuleHandside); ShadowAgent shadowAgent = rr.getMapBefore().get(id); if (shadowAgent == null) { continue; } Link other = shadowAgent.getSiteByName(siteName).getLinkState(); if (!linkState.equalz(other)) { secondListRule.add(rr); } } if (secondListRule.isEmpty()) { InternalState is = headerRule.getMapBefore().get(idInRuleHandside) .getSiteByName(siteName).getInternalState(); for (RootedRule rr : rulesAndGluingThem.keySet()) { Integer id = rulesAndGluingThem.get(rr).get(idInRuleHandside); ShadowAgent shadowAgent = rr.getMapBefore().get(id); if (shadowAgent == null) { continue; } InternalState other = shadowAgent.getSiteByName(siteName) .getInternalState(); if (!is.equalz(other)) { secondListRule.add(rr); } } } if (secondListRule.isEmpty()) { throw new RuntimeException("this site doesn't divide!"); } return secondListRule; } private RootedRulesGroup getNewGroup(List<RootedRule> list) { RootedRulesGroup rg = new RootedRulesGroup(list.get(0)); rulesAndGluingThem.remove(list.get(0)); // TODO Optimize : doesn't need build map each time for (int i = 1; i < list.size(); i++) { rg.tryAdd(list.get(i)); rulesAndGluingThem.remove(list.get(i)); } return rg; } // ===================================================== // utils private void sortAfter(List<Agent> newRightSide) { int i = 0; for (Agent agent : newRightSide) { if (compressed.getMapBefore().get(agent.getIdInRuleHandside()) == null) { continue; } i++; } for (Agent agent : newRightSide) { if (compressed.getMapBefore().get(agent.getIdInRuleHandside()) == null) { agent.setIdInConnectedComponent(i); i++; } } } private void sortBefore(List<Agent> newLeftSide) { int i = 0; for (Agent agent : newLeftSide) { if (compressed.getMapAfter().get(agent.getIdInRuleHandside()) == null) continue; agent.setIdInConnectedComponent(i); compressed.getMapAfter().get(agent.getIdInRuleHandside()) .setIdInConnectedComponent(i); i++; } for (Agent agent : newLeftSide) { if (compressed.getMapAfter().get(agent.getIdInRuleHandside()) == null) { agent.setIdInConnectedComponent(i); i++; } } } // =================================================================== // getters and setters public RootedRule getFirstRule() { return headerRule; } public Rule getCompressedRule() { return buildCompressedRule(); } public void setViews(LocalViewsMain views) { localViews = views; } public Collection<RootedRule> getRules() { return rulesAndGluingThem.keySet(); } public ShadowAgent getObstruction(){ return obstruction; } }