/* A representation of the schedule of all actions in a TDL module in a graph. Copyright (c) 2003-2014 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.domains.tdl.kernel; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Set; import ptolemy.actor.Actor; import ptolemy.actor.Director; import ptolemy.actor.IOPort; import ptolemy.actor.util.Time; import ptolemy.domains.modal.kernel.FSMActor; import ptolemy.domains.modal.kernel.State; import ptolemy.domains.modal.modal.ModalPort; import ptolemy.domains.modal.modal.Refinement; import ptolemy.graph.DirectedGraph; import ptolemy.graph.Edge; import ptolemy.graph.Node; import ptolemy.kernel.util.IllegalActionException; /** * A representation of the schedule of all actions in a TDL module in * a graph. Nodes in this graph describe TDLActions (@see #TDLAction), edges * describe the causal dependencies between those actions. The weight of nodes * are the TDLAction objects, the weight of edges are the time that passes * between two actions. * * @author Patricia Derler @version $Id: TDLActionsGraph.java 70402 2014-10-23 00:52:20Z cxh $ @since Ptolemy II 8.0 */ public class TDLActionsGraph { /** * Create a new TDLActionsGraph for a TDL module. * * @param module * The TDL module. * @param controller * The controller of the TDL module. */ public TDLActionsGraph(TDLModule module, FSMActor controller) { this._controller = controller; this._module = module; } /////////////////////////////////////////////////////////////////// //// public methods //// /** * Build the graph by iterating through all the modes of the TDL module. * Create nodes for transitions, TDL tasks and actuators and connect them. * * @param startmode * This is the initial mode of the TDL module. * @exception IllegalActionException * Thrown if TDL parameters in the module cannot be read. */ public void buildGraph(State startmode) throws IllegalActionException { _graph = new DirectedGraph(); List states = _controller.entityList(); for (State state : states) { Refinement refinement = (Refinement) state.getRefinement()[0]; try { Time modePeriod = ((TDLModuleDirector) _module.getDirector()) .getModePeriod(state); _getTransitions(state, refinement, modePeriod); _getTasks(state, refinement, modePeriod); _getActuators(refinement, modePeriod); } catch (Exception e) { throw new IllegalActionException("Schedule could not be " + "computed; " + e.getMessage()); } _resetsTempVars(); } _connectModes(); System.out.println(_graph.nodeCount()); Node startNode = getNode(new TDLAction(new Time(_module.getDirector(), 0.0), TDLAction.AFTERMODESWITCH, startmode)); if (startNode == null) { startNode = getNode(new TDLAction( ((TDLModuleDirector) _module.getDirector()) .getModePeriod(startmode), TDLAction.AFTERMODESWITCH, startmode)); } } /** * Returns all forward reachable nodes in the graph that are connected to * the given node. Those forward reachable nodes do not depend on other * nodes and the actions defined in the nodes are scheduled to happen at the * same time as the action in the given node. * * @param node * Given node. * @return List of nodes that are forward reachable from the given node. */ public List getEventsFollowingAction(Node node) { return _getForwardReachableIndependentNodes(node, new ArrayList()); } /** * Recursively compute the set of nodes reachable from a given node that * depend on more than one node or are scheduled to happen at a future time. * Examples for the latter are nodes describing the writing of an output * port * * @param justExecuted * Node that was just executed. * @param node * Node from which the reachable Nodes are computed. * @param visited * Already visited nodes, used to avoid loops. * @return Set of reachable nodes that depend on more than one input port or * contain actions that should happen later than the given node. */ public HashMap> getNextJoinNodes(Node justExecuted, Node node, List visited) { if (visited.contains(node)) { return new HashMap(); } else { visited.add(node); } HashMap> events = new HashMap(); List edges = (List) _graph.outputEdges(node); for (Edge edge : edges) { Node targetNode = edge.sink(); if (((TDLAction) targetNode.getWeight()).actionType == TDLAction.MODESWITCH || ((TDLAction) targetNode.getWeight()).actionType == TDLAction.WRITEOUTPUT || ((TDLAction) targetNode.getWeight()).actionType == TDLAction.AFTERMODESWITCH || _graph.inputEdges(targetNode).size() > 1) { List actions = new ArrayList(); Collection backwardEdges = _graph.inputEdges(targetNode); for (Edge backwardNode : backwardEdges) { if (!justExecuted.equals(backwardNode.source())) { actions.add((TDLAction) backwardNode.source() .getWeight()); } } if (actions.size() > 0) { events.put(targetNode, actions); } else { events.putAll(getNextJoinNodes(justExecuted, targetNode, visited)); } } else { events.putAll(getNextJoinNodes(justExecuted, targetNode, visited)); } } return events; } /** * Return the node that is used for the execution of an actor at a certain * time. * * @param invocationTime * Time the actor is being invoked. * @param actor * Actor that is scheduled for that time. * @return The node that is used for the execution of an actor at a certain * time. */ public Node getNode(Time invocationTime, Object actor) { List nodes = (List) _graph.nodes(); for (Node node : nodes) { TDLAction gnode = (TDLAction) node.getWeight(); if (gnode.time.equals(invocationTime) && (gnode.object != null && gnode.object.equals(actor) || gnode.object == null && actor == null)) { return node; } } return null; } /** * Get node for a given TDLAction. * * @param action * Given TDLAction. * @return Node for the given TDLAction. */ public Node getNode(TDLAction action) { List nodes = (List) _graph.nodes(); for (Node node : nodes) { TDLAction gnode = (TDLAction) node.getWeight(); if (gnode.equals(action)) { return node; } } return null; } /** * Get a node which executes a given actor. This output port is written in a * certain time frame defined by the two parameters lower and upper. * * @param actor * Actor that is executed. * @param lower * Lower time bound. * @param upper * Upper time bound. * @return The node used to execute the actor. */ public Node getNode(Object actor, Time lower, Time upper) { List nodes = (List) _graph.nodes(); for (Node node : nodes) { TDLAction gnode = (TDLAction) node.getWeight(); if (gnode.object.equals(actor) && lower.compareTo(gnode.time) <= 0 && upper.compareTo(gnode.time) > 0) { return node; } } return null; } /////////////////////////////////////////////////////////////////// //// private methods //// /** * Add the connections between task output ports and other tasks input * ports. */ private void _addConnectionsBetweenTaskPorts() { Set inputPorts = _tmpConnectedTaskPorts.keySet(); for (IOPort inputPort : inputPorts) { List outputPorts = (List) _tmpConnectedTaskPorts .get(inputPort); for (IOPort outputPort : outputPorts) { // get times when input port is read List