package com.plectix.simulator.staticanalysis.rulecompression; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Stack; import com.plectix.simulator.interfaces.ConnectedComponentInterface; import com.plectix.simulator.simulator.ThreadLocalData; 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.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.AbstractLinkState; import com.plectix.simulator.staticanalysis.abstracting.AbstractSite; import com.plectix.simulator.staticanalysis.localviews.LocalViewsMain; import com.plectix.simulator.staticanalysis.subviews.base.AbstractAction; import com.plectix.simulator.util.io.PlxLogger; public class QuantitativeCompressor { private static final PlxLogger LOGGER = ThreadLocalData .getLogger(QuantitativeCompressor.class); // TODO -> subViews // private IAllSubViewsOfAllAgents allSubViews; private final LocalViewsMain localviews; private Rule compressedRule; private Map<Integer, Agent> mapAfter; private Map<Integer, Agent> mapBefore; private List<Integer> removedList; public QuantitativeCompressor(LocalViewsMain localviews) { this.localviews = localviews; this.compressedRule = null; } public boolean compress(Rule rule) { boolean answer = false; List<ConnectedComponentInterface> listBefore = new LinkedList<ConnectedComponentInterface>(); List<ConnectedComponentInterface> listAfter = new LinkedList<ConnectedComponentInterface>(); mapBefore = new LinkedHashMap<Integer, Agent>(); if (rule.getLeftHandSide() != null) { for (ConnectedComponentInterface c : rule.getLeftHandSide()) { List<Agent> oldLeftSide = new LinkedList<Agent>(c.getAgents()); List<Agent> newLeftSide = RuleCompressionUtils .cloneListOfAgents(oldLeftSide); for (Agent agent : newLeftSide) { mapBefore.put(agent.getIdInRuleHandside(), agent); } } } mapAfter = new LinkedHashMap<Integer, Agent>(); if (rule.getRightHandSide() != null) { for (ConnectedComponentInterface c : rule.getRightHandSide()) { List<Agent> oldRightSide = new LinkedList<Agent>(c.getAgents()); List<Agent> newRightSide = RuleCompressionUtils .cloneListOfAgents(oldRightSide); for (Agent agent : newRightSide) { mapAfter.put(agent.getIdInRuleHandside(), agent); } } } // clean up internal and link states answer = decreaseStates() || answer; // delete unnecessary agents (for example, tested leafs of component) answer = deleteEmptyEnds() || answer; 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 (!removedList.contains(id)) { newLeftSide.add(mapBefore.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 (!removedList.contains(id)) { newRightSide.add(mapAfter.get(id)); } } if (!newRightSide.isEmpty()) { sortAfter(newRightSide); listAfter.add(new ConnectedComponent(newRightSide)); } } } sortNumberInRuleHandSide(); compressedRule = new Rule(listBefore, listAfter, rule.getName() + "_compressed", rule.getRate(), 0, false); return answer; } private void sortNumberInRuleHandSide() { int i = 0; for (int number : mapBefore.keySet()) { while (mapBefore.get(i) != null || mapAfter.get(i) != null) { i++; } if (number < i) { continue; } mapBefore.get(number).setIdInRuleSide(i); if (mapAfter.get(number) != null) { mapAfter.get(number).setIdInRuleSide(i); } i++; } for (int number : mapBefore.keySet()) { while (mapBefore.get(i) != null || mapAfter.get(i) != null) { i++; } if (number < i || mapBefore.get(number) != null) { continue; } mapAfter.get(number).setIdInRuleSide(i); i++; } } private void sortAfter(List<Agent> newRightSide) { int i = 0; for (Agent agent : newRightSide) { if (mapBefore.get(agent.getIdInRuleHandside()) == null) { continue; } i++; } for (Agent agent : newRightSide) { if (mapBefore.get(agent.getIdInRuleHandside()) == null) { agent.setIdInConnectedComponent(i); i++; } } } private void sortBefore(List<Agent> newLeftSide) { int i = 0; for (Agent agent : newLeftSide) { if (mapAfter.get(agent.getIdInRuleHandside()) == null) continue; agent.setIdInConnectedComponent(i); mapAfter.get(agent.getIdInRuleHandside()) .setIdInConnectedComponent(i); i++; } for (Agent agent : newLeftSide) { if (mapAfter.get(agent.getIdInRuleHandside()) == null) { agent.setIdInConnectedComponent(i); i++; } } } boolean decreaseStates() { boolean changed = false; for (int idInRule : mapBefore.keySet()) { changed = decreaseInternalStatesAndFreeLinkStateToWild(mapBefore .get(idInRule), mapAfter.get(idInRule)) || changed; } return changed; } /** * try to remove from rule unnecessary tested agents * * @return */ boolean deleteEmptyEnds() { removedList = new LinkedList<Integer>(); boolean removed = false; Stack<Agent> stack = new Stack<Agent>(); stack.addAll(mapBefore.values()); while (!stack.isEmpty()) { Agent agent = stack.pop(); LOGGER.debug("try do remove as end " + agent.getName()); // may be trouble with empty agents TODO if (agent.getSites().size() > 1 || agent.getSites().size() == 0) { continue; } String siteName = agent.getSites().iterator().next().getName(); Site site = agent.getSiteByName(siteName); if (!(site.getInternalState().isRankRoot())) { continue; } if (site.getLinkState().getStatusLink() != LinkStatus.BOUND) { continue; } if (mapAfter.get(agent.getIdInRuleHandside()) == null) { continue; } Site connectedSite = site.getLinkState().getConnectedSite(); if (connectedSite != null) { if (decreaseLinkSite(site)) { Agent parentAgent = connectedSite.getParentAgent(); if (!stack.contains(parentAgent)) stack.add(parentAgent); // LOGGER.debug("agent before"+mapBefore // .get(parentAgent.getIdInRuleHandside())); // LOGGER.debug("agent after"+mapAfter // .get(parentAgent.getIdInRuleHandside())); decreaseInternalStatesAndFreeLinkStateToWild(mapBefore .get(parentAgent.getIdInRuleHandside()), mapAfter .get(parentAgent.getIdInRuleHandside())); removed = true; // // LOGGER.debug("agent before"+mapBefore // .get(parentAgent.getIdInRuleHandside())); // LOGGER.debug("agent after"+mapAfter // .get(parentAgent.getIdInRuleHandside())); LOGGER.debug("removed as tested end=" + agent); // LOGGER.debug("try to remove as tested end=" + // parentAgent); } } } return removed; } boolean decreaseLinkSite(Site site) { Site connectedSite = site.getLinkState().getConnectedSite(); Agent agent = connectedSite.getParentAgent(); AbstractAgent aAgent = RuleCompressionUtils.clone(agent); int size = localviews.getCountOfCoherentAgent(aAgent); Agent agent2 = mapAfter.get(agent.getIdInRuleHandside()); LOGGER.debug(connectedSite.getName() + " " + aAgent); aAgent.getSiteByName(connectedSite.getName()).getLinkState() .setSemiLink(); if (size == localviews.getCountOfCoherentAgent(aAgent)) { connectedSite.getLinkState().setSemiLink(); if (agent2 != null) { Link linkState = agent2.getSiteByName(connectedSite.getName()) .getLinkState(); if (linkState.getStatusLink() != LinkStatus.FREE) { linkState.setSemiLink(); aAgent.getSiteByName(connectedSite.getName()) .getLinkState().setWildLinkState(); if (size == localviews.getCountOfCoherentAgent(aAgent)) { connectedSite.getLinkState().setWildLinkState(); linkState.setWildLinkState(); LOGGER .debug("decrease link state" + agent2.getSiteByName(connectedSite .getName())); } } } Integer removedId = site.getParentAgent().getIdInRuleHandside(); mapBefore.remove(removedId); mapAfter.remove(removedId); removedList.add(removedId); return true; } return false; } public Rule getCompressedRule() { return compressedRule; } boolean decreaseInternalStatesAndFreeLinkStateToWild(Agent agentBefore, Agent agentAfter) { boolean decreased = false; if (agentBefore == null) { return decreased; } AbstractAction action = new AbstractAction(RuleCompressionUtils .clone(agentBefore), RuleCompressionUtils.clone(agentAfter)); AbstractAgent aAgent = action.getLeftHandSideAgent(); int size = localviews.getCountOfCoherentAgent(aAgent); for (AbstractSite aSite : action.getTestedSites()) { decreased = decreaseInternalState(aAgent, agentBefore .getSiteByName(aSite.getName()), size) || decreased; decreased = decreaseLinkState(aAgent, agentBefore .getSiteByName(aSite.getName()), true, size) || decreased; } if (action.getModificatedSites() != null) { for (AbstractSite aSite : action.getModificatedSites()) { decreased = decreaseInternalState(aAgent, agentBefore .getSiteByName(aSite.getName()), size) || decreased; decreased = decreaseLinkState(aAgent, agentBefore .getSiteByName(aSite.getName()), false, size) || decreased; } } return decreased; } private boolean decreaseLinkState(AbstractAgent aAgent, Site site, boolean tested, int sizeOfProper) { // TODO optimize AbstractLinkState oldLinkState = new AbstractLinkState(aAgent .getSiteByName(site.getName()).getLinkState()); Agent dualAgent = mapAfter.get(site.getParentAgent() .getIdInRuleHandside()); if (oldLinkState.getStatusLink() == LinkStatus.FREE) { aAgent.getSiteByName(site.getName()).getLinkState() .setWildLinkState(); if (sizeOfProper == localviews.getCountOfCoherentAgent(aAgent)) { site.getLinkState().setWildLinkState(); if (dualAgent != null) { Link linkState = dualAgent.getSiteByName(site.getName()) .getLinkState(); if (linkState.getStatusLink() == LinkStatus.FREE) { linkState.setWildLinkState(); } } if (tested && site.getInternalState().hasDefaultName()) { site.getParentAgent().removeSite(site.getName()); if (dualAgent != null) { dualAgent.removeSite(site.getName()); } } return true; } aAgent.getSiteByName(site.getName()).setLinkState(oldLinkState); return false; } else { if (oldLinkState.getStatusLink() == LinkStatus.BOUND) { return false; // wildcard case } else { if (tested && site.getInternalState().hasDefaultName()) { site.getParentAgent().removeSite(site.getName()); dualAgent.removeSite(site.getName()); return true; } return false; } } } private boolean decreaseInternalState(AbstractAgent aAgent, Site site, int sizeOfProper) { // TODO optimize String oldInternal = aAgent.getSiteByName(site.getName()) .getInternalState().getName(); aAgent.getSiteByName(site.getName()).getInternalState().setName( InternalState.DEFAULT_NAME); if (sizeOfProper == localviews.getCountOfCoherentAgent(aAgent)) { site.getInternalState().setName(InternalState.DEFAULT_NAME); return true; } aAgent.getSiteByName(site.getName()).getInternalState().setName( oldInternal); return false; } }