package com.plectix.simulator.staticanalysis.stories.compressions; import java.util.ArrayList; import java.util.Iterator; import java.util.Map.Entry; import com.plectix.simulator.staticanalysis.stories.ActionOfAEvent; import com.plectix.simulator.staticanalysis.stories.TypeOfWire; import com.plectix.simulator.staticanalysis.stories.storage.AbstractState; import com.plectix.simulator.staticanalysis.stories.storage.AtomicEvent; import com.plectix.simulator.staticanalysis.stories.storage.EventInterface; import com.plectix.simulator.staticanalysis.stories.storage.EventIteratorInterface; import com.plectix.simulator.staticanalysis.stories.storage.StateOfLink; import com.plectix.simulator.staticanalysis.stories.storage.StoryStorageException; import com.plectix.simulator.staticanalysis.stories.storage.WireHashKey; import com.plectix.simulator.staticanalysis.stories.storage.WireStorageInterface; /*package*/final class StrongCompression { private final CompressionPassport passport; private final WeakCompression weak; private final ArrayList<Long> agents1 = new ArrayList<Long>(); private final ArrayList<Long> agents2 = new ArrayList<Long>(); public StrongCompression(CompressionPassport passport) { this.passport = passport; this.weak = new WeakCompression(passport.getStorage()); } public final void process() throws StoryStorageException { boolean improved = true; // StoryCorrectness.testLinks(passport.getStorage()); weak.process(); passport.removeEventWithMarkDelete(); while (improved) { improved = false; if (passport.eventCount() < 3) return; EventIteratorInterface eventIterator1 = passport .eventIterator(false); EventIteratorInterface eventIterator2 = passport .eventIterator(true); while (eventIterator1.hasNext() && eventIterator2.hasNext()) { // TODO > -> >= if (eventIterator1.next() > eventIterator2.next()) break; EventInterface event1 = eventIterator1.value(); EventInterface event2 = eventIterator2.value(); if ((event1.getStepId() != -1 && lookThroughPerturbations( event1, true)) || lookThroughPerturbations(event2, false)) { improved = true; break; } } } } private final boolean lookThroughPerturbations(EventInterface event, boolean swapTop) throws StoryStorageException { Iterator<String> typeIterator = passport.agentTypeIterator(); boolean improved = false; // System.out.println(event.getStepId() + " : event"); while (typeIterator.hasNext() && !improved) { String type = typeIterator.next(); Iterator<Long> agentIterator1 = passport.agentIterator(type); while (agentIterator1.hasNext() && !improved) { Long agentId1 = agentIterator1.next(); Iterator<Long> agentIterator2 = passport.agentIterator(type); while (agentIterator2.hasNext()) if (agentIterator2.next() == agentId1) break; while (agentIterator2.hasNext() && !improved) { Long agentId2 = agentIterator2.next(); if (!extendSwap(event, agentId1, agentId2, swapTop)) continue; EventInterface neiEvent = passport.swapAgents(agents1, agents2, event.getStepId(), swapTop); // TODO: remember swapped pairs if (weak.processInconsistent(event, neiEvent)) { improved = true; passport.removeEventWithMarkDelete(); //System.out.println("work!!"); } else passport.undoSwap(); // StoryCorrectness.testLinks(passport.getStorage()); } } } return improved; } private final boolean doesAgentMatter(EventInterface event, Long agentId) { ArrayList<WireHashKey> wires = passport.getAgentWires(agentId); for (WireHashKey wire : wires) if (event.containsWire(wire)) return true; return false; } // TODO: may be should start from neiEvent... private final boolean extendSwap(EventInterface event, Long agentId1, Long agentId2, boolean swapTop) throws StoryStorageException { int curPair = 0; agents1.clear(); agents2.clear(); agents1.add(agentId1); agents2.add(agentId2); if (!doesAgentMatter(event, agentId1) && !doesAgentMatter(event, agentId2)) return false; while (curPair != agents1.size()) { if (!extendPair(event, curPair, swapTop)) return false; curPair++; } return true; } final boolean extendPair(EventInterface event, int pairIdx, boolean swapTop) throws StoryStorageException { Long agentId1 = agents1.get(pairIdx); Long agentId2 = agents2.get(pairIdx); if (!passport.isAbleToSwap(agentId1, agentId2)) return false; ArrayList<WireHashKey> wires1 = passport.getAgentWires(agentId1); ArrayList<WireHashKey> wires2 = passport.getAgentWires(agentId2); WireStorageInterface storage = passport.getStorage(); for (WireHashKey w1 : wires1) { WireHashKey w2 = null; if (w1.getTypeOfWire() != TypeOfWire.LINK_STATE) continue; for (WireHashKey _w2 : wires2) { if (_w2.getTypeOfWire() == TypeOfWire.LINK_STATE && w1.getSiteName() == _w2.getSiteName()) { w2 = _w2; break; } } if (w2 == null) throw new StoryStorageException("extendPair: different agents"); // Long upperEventId1 = storage.getStorageWires().get(w1).floorKey( // event.getStepId()); // Long upperEventId2 = storage.getStorageWires().get(w2).floorKey( // event.getStepId()); // // if (!swapTop && upperEventId1 != null // && upperEventId1.equals(event.getStepId())) // upperEventId1 = storage.getStorageWires().get(w1).lowerKey( // event.getStepId()); // if (!swapTop && upperEventId2 != null // && upperEventId2.equals(event.getStepId())) // upperEventId2 = storage.getStorageWires().get(w2).lowerKey( // event.getStepId()); // // AtomicEvent<?> event1 = null; // AtomicEvent<?> event2 = null; // // if (upperEventId1 != null) // event1 = storage.getStorageWires().get(w1).get(upperEventId1); // if (upperEventId2 != null) // event2 = storage.getStorageWires().get(w2).get(upperEventId2); // // StateOfLink state1 = getStateInSpace(event1); // StateOfLink state2 = getStateInSpace(event2); // // if (state1 == null && state2 == null) // continue; // // if (state1 == null || state2 == null) // return false; // // if (passport.getAgentType(state1.getAgentId()) != passport // .getAgentType(state2.getAgentId())) // return false; // // if (!state1.getSiteName().equals(state2.getSiteName())) // return false; // // if (!isStateTesting(w1, upperEventId1) // && !isStateTesting(w2, upperEventId2)) // continue; AbstractState<?> lowerState1 = null; AbstractState<?> lowerState2 = null; boolean b = true; StateOfLink tmpState1 = null; StateOfLink tmpState2 = null; if (swapTop) { Entry<Long, AtomicEvent<?>> higherEntry1 = storage .getStorageWires().get(w1).higherEntry( event.getStepId()); Entry<Long, AtomicEvent<?>> higherEntry2 = storage .getStorageWires().get(w2).higherEntry( event.getStepId()); if (higherEntry1 == null && higherEntry2 == null) { Entry<Long, AtomicEvent<?>> floorEntry1 = storage .getStorageWires().get(w1).floorEntry( event.getStepId()); Entry<Long, AtomicEvent<?>> floorEntry2 = storage .getStorageWires().get(w2).floorEntry( event.getStepId()); // reinsurance if (floorEntry1 == null || floorEntry2 == null) { return false; } b = false; tmpState1 = getStateInSpace(floorEntry1.getValue()); tmpState2 = getStateInSpace(floorEntry2.getValue()); //reinsurance if(tmpState1==null||tmpState2==null) return false; } if (higherEntry1 == null ^ higherEntry2 == null) { // TODO optimize this case. we can return true in this case return false; } if (b) { lowerState1 = higherEntry1.getValue().getState(); lowerState2 = higherEntry2.getValue().getState(); } } else { Entry<Long, AtomicEvent<?>> ceilingEntry1 = storage .getStorageWires().get(w1).ceilingEntry( event.getStepId()); Entry<Long, AtomicEvent<?>> ceilingEntry2 = storage .getStorageWires().get(w2).ceilingEntry( event.getStepId()); if (ceilingEntry1 == null && ceilingEntry2 == null) { continue; } if (ceilingEntry1 == null ^ ceilingEntry2 == null) { // TODO optimize this case. we can return true in this case return false; } lowerState1 = ceilingEntry1.getValue().getState(); lowerState2 = ceilingEntry2.getValue().getState(); } StateOfLink state1 = null; StateOfLink state2 = null; if (b) { Object beforeState1 = lowerState1.getBeforeState(); Object beforeState2 = lowerState2.getBeforeState(); if (beforeState1 == null && beforeState2 == null) continue; if ((beforeState1 != null && beforeState2 == null) || (beforeState1 == null && beforeState2 != null)) return false; state1 = (StateOfLink) beforeState1; state2 = (StateOfLink) beforeState2; } else { state1 = tmpState1; state2 = tmpState2; } if (state1.isFree() && state2.isFree()) continue; if (state1.isFree() ^ state2.isFree()) return false; if (!state1.getSiteName().equals(state2.getSiteName())) return false; if (passport.getAgentType(state1.getAgentId()) != passport .getAgentType(state2.getAgentId())) return false; if (agents2.contains(state1.getAgentId()) || agents1.contains(state2.getAgentId())) return false; boolean cont1 = agents1.contains(state1.getAgentId()); boolean cont2 = agents2.contains(state2.getAgentId()); if (cont1 != cont2) return false; else { if (cont1 && !checkCoincidence(state1.getAgentId(), state2 .getAgentId())) { return false; } else { agents1.add(state1.getAgentId()); agents2.add(state2.getAgentId()); } } } return true; } boolean checkCoincidence(Long first, Long second) throws StoryStorageException { long number1 = -1; long number2 = -1; for (int i = 0; i < agents1.size(); i++) { if (agents1.get(i).equals(first)) { number1 = agents1.get(i); break; } } for (int i = 0; i < agents2.size(); i++) { if (agents2.get(i).equals(second)) { number2 = agents2.get(i); break; } } if (number1 == -1 || number2 == -1) { throw new StoryStorageException("agent coincides"); } if (number1 != number2) return false; return true; } private final StateOfLink getStateInSpace(AtomicEvent<?> event) { if (event != null) { StateOfLink state = null; switch (event.getType()) { case TEST: state = (StateOfLink) event.getState().getBeforeState(); break; case MODIFICATION: state = (StateOfLink) event.getState().getAfterState(); break; case TEST_AND_MODIFICATION: state = (StateOfLink) event.getState().getAfterState(); break; } // if (state != null && !state.isFree()) return state; } return null; } private final boolean isStateTesting(WireHashKey wKey, Long uppedId) { Entry<Long, AtomicEvent<?>> event = passport.getStorage() .getStorageWires().get(wKey).higherEntry(uppedId); if (event != null) { if (event.getValue().getType() == ActionOfAEvent.MODIFICATION && event.getValue().getState().getBeforeState() == null) return false; return true; } return false; } }