/*
* Copyright (c) 2009, IETR/INSA of Rennes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.frontend.schedule;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import java.util.List;
import net.sf.orcc.cal.cal.AstTag;
import net.sf.orcc.cal.cal.Inequality;
import net.sf.orcc.cal.cal.Priority;
import net.sf.orcc.df.Action;
import net.sf.orcc.df.DfFactory;
import net.sf.orcc.df.Tag;
import org.jgrapht.DirectedGraph;
import org.jgrapht.ext.DOTExporter;
import org.jgrapht.ext.VertexNameProvider;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.traverse.TopologicalOrderIterator;
/**
* This class defines a function to sort actions based on the priorities
* defined.
*
* @author Matthieu Wipliez
*
*/
public class ActionSorter {
/**
* This class defines a {@link VertexNameProvider} for actions. The
* {@link #getVertexName(Action)} simply calls the <code>toString</code>
* method of the given action.
*
* @author Matthieu Wipliez
*
*/
private class ActionNameProvider implements VertexNameProvider<Action> {
@Override
public String getVertexName(Action action) {
return action.toString();
}
}
private ActionList actionList;
private DirectedGraph<Action, DefaultEdge> graph;
/**
* Creates a new action sorter.
*
* @param actionList
* an action list
*/
public ActionSorter(ActionList actionList) {
graph = new DefaultDirectedGraph<Action, DefaultEdge>(DefaultEdge.class);
this.actionList = actionList;
}
/**
* Creates a list of actions based on the given priorities.
*
* @param priorities
*/
public ActionList applyPriority(List<Priority> priorities) {
buildGraph(priorities);
ActionList actions = new ActionList();
// adds untagged actions by document order
for (Action action : actionList) {
if (action.getTag().isEmpty()) {
actions.add(action);
}
}
// topological sort only work for graphs with no cycles
// cycle detection is done in the validator
TopologicalOrderIterator<Action, DefaultEdge> it = new TopologicalOrderIterator<Action, DefaultEdge>(
graph);
// adds tagged actions by priority order
while (it.hasNext()) {
Action action = it.next();
actions.add(action);
}
return actions;
}
/**
* Builds the priority graph from the given priorities and action list. The
* algorithm is pretty straightforward.
*
* <pre>
* for every inequality of the form t(1) > t(2) > ... > t(n)
* for every pair of tags (t(i), t(i+1)) where 1 <= i < n
* link all actions matching t(i) to all actions matching t(i+1)
* </pre>
*
* <p>
* A tag that references no action is an error.
* </p>
* <p>
* Named actions (ie whose tag is not empty) that are in the action list but
* are not referenced by priorities are added to the priority graph but are
* not linked to any other action, therefore their order will be unknown.
* </p>
*
* @param priorities
* a list of inequalities, an inequality being a list of tags
* (and a tag is a list of strings)
*/
private void buildGraph(List<Priority> priorities) {
for (Action action : actionList) {
if (!action.getTag().isEmpty()) {
graph.addVertex(action);
}
}
for (Priority priority : priorities) {
for (Inequality inequality : priority.getInequalities()) {
// the grammar requires there be at least two tags
Iterator<AstTag> it = inequality.getTags().iterator();
Tag previousTag = DfFactory.eINSTANCE.createTag(it.next()
.getIdentifiers());
while (it.hasNext()) {
Tag tag = DfFactory.eINSTANCE.createTag(it.next()
.getIdentifiers());
List<Action> sources = actionList
.getTaggedActions(previousTag);
List<Action> targets = actionList.getTaggedActions(tag);
for (Action source : sources) {
for (Action target : targets) {
graph.addEdge(source, target);
if (target.hasAttribute("IsPrecededBy")) {
String oldStr = target.getValueAsString("IsPrecededBy");
String newStr = oldStr.concat("-" + source.getName());
target.setAttribute("IsPrecededBy", newStr);
} else {
target.addAttribute("IsPrecededBy");
target.setAttribute("IsPrecededBy", source.getName());
}
}
}
previousTag = tag;
}
}
}
}
/**
* Prints the priority graph to the given output stream
*
* @param out
* an output stream
*/
public void printGraph(OutputStream out) {
VertexNameProvider<Action> provider = new ActionNameProvider();
DOTExporter<Action, DefaultEdge> exporter = new DOTExporter<Action, DefaultEdge>(
provider, null, null);
exporter.export(new OutputStreamWriter(out), graph);
}
}