// Expand the P-APGAN-clustered graph. The schedule element that is // returned has an iteration count of 1. This iteration count expression // can be changed by the caller to iterate the schedule computed in // this method. // @param graph The graph containing the node. // @param node The super node to expand. // @param apgan The scheduler that was used to build the cluster hierarchy. // @return The schedule saving the expansion result. private SymbolicScheduleElement _expandAPGAN( PSDFGraph graph, ptolemy.graph.Node node, PSDFAPGANStrategy strategy) { PSDFGraph childGraph = (PSDFGraph) strategy.getClusterManager().getSubgraph(node); try { // Atomic node if (childGraph == null) { PSDFNodeWeight weight = (PSDFNodeWeight) node.getWeight(); SymbolicFiring firing = new SymbolicFiring((Actor) weight.getComputation(), "1"); return firing; // Super node } else { // FIXME: why call new Schedule here? /*Schedule schedule = */ new Schedule(); // Expand the super node with adjacent nodes contained // within it. Edge edge = (Edge) childGraph.edges().iterator().next(); ptolemy.graph.Node source = edge.source(); ptolemy.graph.Node sink = edge.sink(); SymbolicScheduleElement first = _expandAPGAN(childGraph, source, strategy); SymbolicScheduleElement second = _expandAPGAN(childGraph, sink, strategy); // Determine the iteration counts of the source and // sink clusters. String producedExpression = strategy.producedExpression(edge); String consumedExpression = strategy.consumedExpression(edge); // These errors should not occur. if (producedExpression == null) { throw new RuntimeException( "Internal error: null " + "production rate expression. The offending edge " + "follows.\n" + edge); } else if (consumedExpression == null) { throw new RuntimeException( "Internal error: null " + "consumption rate expression. The offending edge " + "follows.\n" + edge); } String denominator = PSDFGraphs.gcdExpression(producedExpression, consumedExpression); String firstIterations = "(" + consumedExpression + ") / (" + denominator + ")"; String secondIterations = "(" + producedExpression + ") / (" + denominator + ")"; first.setIterationCount(firstIterations); second.setIterationCount(secondIterations); SymbolicSchedule symbolicSchedule = new SymbolicSchedule("1"); symbolicSchedule.add((ScheduleElement) first); symbolicSchedule.add((ScheduleElement) second); // Compute buffer sizes and associate them with the // corresponding relations. Iterator edges = childGraph.edges().iterator(); while (edges.hasNext()) { Edge nextEdge = (Edge) edges.next(); PSDFEdgeWeight weight = (PSDFEdgeWeight) nextEdge.getWeight(); IOPort sourcePort = weight.getSourcePort(); List relationList = sourcePort.linkedRelationList(); if (relationList.size() != 1) { // FIXME: Need to generalize this? throw new RuntimeException( "Cannot handle relation " + "lists that are not singletons.\n" + "The size of this relation list is " + relationList.size() + "\nA dump of the offending edge follows.\n" + nextEdge + "\n"); } Iterator relations = relationList.iterator(); Relation relation = (Relation) relations.next(); String produced = strategy.producedExpression(nextEdge); String consumed = strategy.consumedExpression(nextEdge); String bufferSizeExpression = "((" + produced + ") * (" + consumed + ")) / " + PSDFGraphs.gcdExpression(produced, consumed); // Due to the bottom-up traversal in _expandAPGAN, // relations that are linked to multiple sink // nodes will have their buffer sizes // progressively replaced by those of outer // clusterings, and will end up with the buffer // size determined by the outermost clustering. _debug( "Associating buffer size expression '" + bufferSizeExpression + "' with relation '" + relation.getName() + "'\n"); _bufferSizeMap.put(relation, bufferSizeExpression); } return symbolicSchedule; } } catch (Throwable throwable) { throw new KernelRuntimeException( throwable, "Error converting cluster hierarchy to " + "schedule.\n"); } }