private Set<Reaction<T>> initCandidates(final Reaction<T> newReaction, final Context c) { if (c.equals(Context.GLOBAL)) { return hndlrs.keySet(); } final Set<Reaction<T>> list = new LinkedHashSet<>(); addNeighborhoodReactions(list, newReaction); if (c.equals(Context.LOCAL)) { addLocalReactions(list, newReaction); } else { addExtendedNeighborhoodReactions(list, newReaction); } return list; }
@Override public void createDependencies(final DependencyHandler<T> rh) { createDependencies(rh, rh.getReaction()); }
private void createDependencies(final DependencyHandler<T> newHandler, final Reaction<T> newReaction) { /* * Will contain the reactions potentially influencing the new one */ final Iterable<Reaction<T>> inputCandidates = initCandidates(newReaction, newReaction.getInputContext()); /* * Will contain the reactions possibly influenced by the new one */ final Iterable<Reaction<T>> outputCandidates = initCandidates(newReaction, newReaction.getOutputContext()); /* * keySet() is not guaranteed to preserve the ordering. This can lead to * bad behaviors, since may change the order by which the reactions are * updated, and consequently ruin the predictability */ for (final Reaction<T> r : inputCandidates) { if (mayInfluence(r, newReaction) && influences(r, newReaction.getInfluencingMolecules())) { final DependencyHandler<T> dep = hndlrs.get(r); dep.addOutDependency(newHandler); newHandler.addInDependency(dep); } } for (final Reaction<T> r : outputCandidates) { if (mayInfluence(newReaction, r) && influences(newReaction, r.getInfluencingMolecules())) { final DependencyHandler<T> dep = hndlrs.get(r); newHandler.addOutDependency(dep); dep.addInDependency(newHandler); } } }
@Override public void addNeighbor(final Node<T> n1, final Node<T> n2) { DependencyHandler<T> rh1, rh2; for (final Reaction<T> r1 : n1.getReactions()) { rh1 = hndlrs.get(r1); for (int j = 0; j < n2.getReactions().size(); j++) { final Reaction<T> r2 = n2.getReactions().get(j); if (mayInfluence(r2, r1) && influences(r2, r1.getInfluencingMolecules())) { rh2 = hndlrs.get(r2); if (!rh1.isInfluenced().contains(rh2)) { rh1.addInDependency(rh2); } if (!rh2.influences().contains(rh1)) { rh2.addOutDependency(rh1); } } if (mayInfluence(r1, r2) && influences(r1, r2.getInfluencingMolecules())) { rh2 = hndlrs.get(r2); if (!rh2.isInfluenced().contains(rh1)) { rh2.addInDependency(rh1); } if (!rh1.influences().contains(rh2)) { rh1.addOutDependency(rh2); } } } } }
/** * Builds a simulation for a given environment. By default it uses a * DependencyGraph and an IndexedPriorityQueue internally. If you want to * use your own implementations of {@link DependencyGraph} and * {@link ReactionManager} interfaces, don't use this constructor. * * @param e * the environment at the initial time * @param maxSteps * the maximum number of steps to do * @param t * the maximum time to reach */ public Engine(final Environment<T> e, final long maxSteps, final Time t) { L.trace("Engine created"); env = e; env.setSimulation(this); dg = new MapBasedDependencyGraph<T>(env, handlers); ipq = new ArrayIndexedPriorityQueue<>(); this.steps = maxSteps; this.finalTime = t; }
@Override public void removeNeighbor(final Node<T> n1, final Node<T> n2) { DependencyHandler<T> rh1, rh2; for (final Reaction<T> r1 : n1.getReactions()) { rh1 = hndlrs.get(r1); for (final Reaction<T> r2 : n2.getReactions()) { rh2 = hndlrs.get(r2); if (!mayInfluence(r2, r1)) { rh1.removeInDependency(rh2); rh2.removeOutDependency(rh1); /* * Dependencies addition or removal should not influence the * next scheduled execution time. */ } if (!mayInfluence(r1, r2)) { rh2.removeInDependency(rh1); rh1.removeOutDependency(rh2); /* * Dependencies addition or removal should not influence the * next scheduled execution time. */ } } } } }
private boolean mayInfluence(final Reaction<T> source, final Reaction<T> target) { final Context in = target.getInputContext(); final Context out = source.getOutputContext(); if (// Same node target.getNode().equals(source.getNode()) // If reaction writes something globally || out.equals(Context.GLOBAL) // If reaction reads something globally || in.equals(Context.GLOBAL)) { return true; } return influenceNeighborCheck(env, source, target, in, out); }
/** * This method checks if there may be a dependency considering the * neighborhoods */ private static <T> boolean influenceNeighborCheck(final Environment<T> env, final Reaction<T> source, final Reaction<T> target, final Context in, final Context out) { final Neighborhood<T> sn = env.getNeighborhood(source.getNode()); final boolean scn = in.equals(Context.NEIGHBORHOOD); // If source reads from neighborhood and target is within if (scn && sn.contains(target.getNode())) { return true; } // If target writes in neighborhood and source is within final Neighborhood<T> tn = env.getNeighborhood(target.getNode()); final boolean tcn = out.equals(Context.NEIGHBORHOOD); if (tcn && tn.contains(source.getNode())) { return true; } // If source writes on the neighborhood, target reads on its // neighborhood and there is at least one common node return scn && tcn && commonNeighbor(env, sn, target.getNode()); }