package com.plectix.simulator.staticanalysis.observables; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import com.plectix.simulator.interfaces.ConnectedComponentInterface; import com.plectix.simulator.interfaces.ObservableConnectedComponentInterface; import com.plectix.simulator.interfaces.ObservableInterface; import com.plectix.simulator.simulator.options.SimulatorArgumentsDefaultValues; import com.plectix.simulator.staticanalysis.ObservableConnectedComponent; import com.plectix.simulator.staticanalysis.ObservableRuleComponent; import com.plectix.simulator.staticanalysis.Rule; import com.plectix.simulator.util.OutputUtils; /** * This class describes observables storage. This is the set of objects, which * we want to keep an eye on during the simulation. * * In fact such objects are rules and substances. * * @see ObservableConnectedComponent * @see ObservableRuleComponent * @author evlasov * */ public class Observables { private boolean ocamlStyleObsName = false; private boolean unifiedTimeSeriesOutput = false; private final List<ObservableState> countTimeList = new ArrayList<ObservableState>();; private final List<ObservableConnectedComponentInterface> connectedComponentList = new ArrayList<ObservableConnectedComponentInterface>();; private List<ObservableInterface> componentList = new ArrayList<ObservableInterface>(); private double timeNext; private double timeSampleMin; private List<ObservableInterface> componentListForXMLOutput = null; private final ObservableComponentsManager componentManager = new ObservableComponentsManager(this); /** * This method initializes CObservables within external parameters * * @param fullTime * total time of simulation * @param initialTime * time starting point * @param events * number of events * @param points * precision (number of points) of observables state graphic * @param isTime * <tt>true</tt>, if we have to save an information about current * time and observables list, otherwise <tt>false</tt> */ public final void init(double fullTime, double initialTime, long events, int points, boolean isTime) { timeSampleMin = 0.; timeNext = 0.; if (isTime) { if (initialTime > 0.0) { timeNext = initialTime; fullTime = fullTime - timeNext; this.initializeMinSampleTime(fullTime, points); } else { this.initializeMinSampleTime(fullTime, points); timeNext = timeSampleMin; } } else { if (initialTime > 0) { timeNext = initialTime; events = events - Math.round(timeNext); this.initializeMinSampleTime(events, points); } else { this.initializeMinSampleTime(events, points); timeNext = timeSampleMin; } } } /** * This method resets all the information in CObservables. We use it when * we've got more than on simulation in one time. */ public final void resetLists() { countTimeList.clear(); componentListForXMLOutput = null; componentList.clear(); connectedComponentList.clear(); } /** * This method sets default value for the minimal difference of two time * points on the "x" axis in graphic for observables. * * @param simulationParameter * is double parameter vary on the simulation type * @param points * is the quantity of points on the "x" axis in observables * graphic */ private final void initializeMinSampleTime(double simulationParameter, int points) { if (points == -1) { timeSampleMin = (simulationParameter / SimulatorArgumentsDefaultValues.DEFAULT_NUMBER_OF_POINTS); } else { timeSampleMin = (simulationParameter / points); } } /** * This method handles observables in current time/event. If there's need to * save information about observables state (quantity, activity, etc), it * saves it. * * @param time * current time * @param count * current event number * @param isTime * <tt>true</tt>, if we have to save an information about current * time and observables list, otherwise <tt>false</tt> */ public final void calculateObs(double time, long count, boolean isTime) { if (isTime) { if (time < timeNext) return; } else { if (count < timeNext) return; } updateLastValues(); calculateAll(false); addToCountTimeList(time, count); timeNext += timeSampleMin; } public final void calculateExactSampleObs(double time, long count, boolean isTime) { if (isTime) { if (time < timeNext) return; updateLastValues(); while (time >= timeNext) { calculateAll(false); addToCountTimeList(timeNext, count); timeNext += timeSampleMin; } } else { if (count < timeNext) return; updateLastValues(); calculateAll(false); addToCountTimeList(timeNext, count); timeNext += timeSampleMin; } } /** * This method saves current observables state (quantity, activity, etc). * * @param replaceLast * <tt>true</tt> if we need to overwrite the latest information, * or <tt>false</tt> if we don't */ private final void calculateAll(boolean replaceLast) { for (ObservableInterface cc : componentList) { cc.fixState(replaceLast); } } /** * This method handles information on observables in the latest moment of * simulation * * @param time * current time */ public final void updateLastValues() { for (ObservableInterface cc : componentList) { cc.updateLastValue(); } } /** * This method saves observables state (quantity, activity, etc) in the * latest moment of simulation. * * @param time * current time */ public final void calculateObsLast(double time, long event) { int size = countTimeList.size(); if (size == 0) return; if (Math.abs(countTimeList.get(size - 1).getTime() - time) < 1e-16) return; updateLastValues(); addToCountTimeList(time, event); calculateAll(false); } private void addToCountTimeList(double time, long event) { if (unifiedTimeSeriesOutput) countTimeList.add(new ObservableState(time, event)); else countTimeList.add(new ObservableState(time)); } // --------------------------ADDERS------------------------------------------ /** * This method creates observable component using list of connected * components from solution * * @param list * list of connected componetns from solution * @param name * name of the observable * @param line * kappa file line, which describes this observable component * @param observableId * observable id */ public final void addConnectedComponents( List<ConnectedComponentInterface> list, String name, String line, int observableId) { boolean unique; if (list.size() > 1) unique = false; else unique = true; if (ocamlStyleObsName) { line = OutputUtils.printPartRule(list, ocamlStyleObsName); } for (ConnectedComponentInterface component : list) { ObservableConnectedComponentInterface oCC = new ObservableConnectedComponent( component.getAgents(), name, line, observableId, unique); oCC.initSpanningTreeMap(); connectedComponentList.add(oCC); componentList.add(oCC); } } /** * This method returns adds Observable-rule from given collection of rules * by it's name * * @param name * name of the rule * @param observableRuleID * new observable rule id * @param rules * list of rules * @return <tt>true</tt> if we've founded and added such rule to * observables, otherwise <tt>false</tt> */ public final boolean addRulesName(String name, int observableRuleID, List<Rule> rules) { for (Rule rule : rules) { if ((rule.getName() != null) && (rule.getName().equals(name))) { ObservableRuleComponent obsRC = new ObservableRuleComponent( rule, observableRuleID); componentList.add(obsRC); return true; } } return false; } /** * For each observable component this method calculates whether it's unique * canonical representative or not and saves this information to the * component */ public final void checkAutomorphisms() { for (ObservableConnectedComponentInterface oCC : connectedComponentList) { if (oCC.getMainAutomorphismNumber() == ObservableConnectedComponent.NO_INDEX) { for (ObservableConnectedComponentInterface oCCIn : connectedComponentList) { if (!(oCC == oCCIn) && oCCIn.getMainAutomorphismNumber() == ObservableConnectedComponent.NO_INDEX) { if (oCC.getAgents().size() == oCCIn.getAgents().size()) if (oCC.isAutomorphicTo(oCCIn.getAgents().get(0))) { int index = connectedComponentList.indexOf(oCC); oCC.addAutomorphicObservables(index); oCCIn.setMainAutomorphismNumber(index); } } } } } } // ------------------------GETTERS AND SETTERS------------------------------ /** * This method returns minimal difference between two time points in graphic * for observables, i.e. precision. * * @return minimal difference between two time points in graphic for * observables. */ public final double getTimeSampleMin() { return timeSampleMin; } /** * This method returns list of time-points on "x" axis in graphic for * observables. * * @return list of time-points on "x" axis in graphic for observables. */ public final List<ObservableState> getCountTimeList() { return countTimeList; } public final List<ObservableInterface> getComponentList() { return componentList; } public final List<ObservableInterface> getUniqueComponentList() { if (componentListForXMLOutput == null) { Set<Integer> set = new LinkedHashSet<Integer>(); List<ObservableInterface> list = new ArrayList<ObservableInterface>(); for (ObservableInterface cc : componentList) { if (!set.contains(cc.getId())) { set.add(cc.getId()); list.add(cc); } } componentListForXMLOutput = list; } return componentListForXMLOutput; } public final List<ObservableConnectedComponentInterface> getConnectedComponentList() { return connectedComponentList; } public final List<ObservableConnectedComponentInterface> getConnectedComponentListForXMLOutput() { Set<Integer> map = new LinkedHashSet<Integer>(); List<ObservableConnectedComponentInterface> list = new LinkedList<ObservableConnectedComponentInterface>(); for (ObservableConnectedComponentInterface cc : connectedComponentList) { if (!map.contains(cc.getId())) { map.add(cc.getId()); list.add(cc); } } return list; } public final void setOcamlStyleObsName(boolean ocamlStyleObsName) { this.ocamlStyleObsName = ocamlStyleObsName; } public final void setUnifiedTimeSeriesOutput(boolean unifiedTimeSeriesOutput) { this.unifiedTimeSeriesOutput = unifiedTimeSeriesOutput; } public void addInitialState() { updateLastValues(); addToCountTimeList(0.0, 0); calculateAll(false); } public void setComponentList(List<ObservableInterface> componentList) { this.componentList = componentList; } public final ObservableComponentsManager getComponentManager() { return componentManager; } }