4 Incheckningar 340f430de4 ... 6a1e752a60

Upphovsman SHA1 Meddelande Datum
  Claudio Gomes 6a1e752a60 Merge branch 'master' of msdl.uantwerpen.be:claudio/HintCO 5 år sedan
  Claudio Gomes f2748b390b skeleton of A* search algorithm made. 5 år sedan
  Claudio Gomes 6d509da0b7 more renaming 5 år sedan
  Claudio Gomes 5bc4bafbd2 refactor: change PrecendenceNode (typo) to PrecedenceNode 5 år sedan

+ 1 - 0
HintCOEngine/.classpath

@@ -25,5 +25,6 @@
 			<attribute name="javadoc_location" value="jar:platform:/resource/HintCOEngine/lib/jgrapht-core-1.3.1-javadoc.jar!/"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry kind="lib" path="lib/jheaps-0.13.jar"/>
 	<classpathentry kind="output" path="output"/>
 </classpath>

BIN
HintCOEngine/lib/jheaps-0.13.jar


+ 31 - 0
HintCOEngine/src/ua/ansymo/hintco/AlgebraicLoopVariantProcessor.xtend

@@ -2,8 +2,11 @@ package ua.ansymo.hintco
 
 import java.util.Deque
 import org.eclipse.core.runtime.Assert
+import org.jgrapht.alg.interfaces.AStarAdmissibleHeuristic
+import org.jgrapht.alg.shortestpath.AStarShortestPath
 import org.jgrapht.graph.DirectedMultigraph
 import org.jgrapht.util.SupplierUtil
+import org.jgrapht.graph.DefaultWeightedEdge
 
 class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 	
@@ -52,6 +55,28 @@ class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 		return resultGraph
 	}
 	
+	/*
+	 * Solves the optimization problem for a given strong component.
+	 * 1. Builds the search graph.
+	 * 2. Uses AStar algorithm (from JGraph lib) to find the optimal solution.
+	 */
+	def findOptimalTriggerSequenceStrongComponent(DirectedMultigraph<CosimUnitInstance, DefaultWeightedEdge> sc) {
+		val searchGraph = new LazySearchTree(sc)
+		val alg = new AStarShortestPath(searchGraph, new BasicHeuristic())
+		alg.getPath(searchGraph.root, searchGraph.bottom)
+	}
+	
+	/*
+	 * Solves the optimization problem for each strong component in the given graph.
+	 * 1. Compute strong components.
+	 * 2. For each component SC:
+	 * 2.1 Find the optimal trigger sequence
+	 * 3. Join the trigger sequences found for each component, and return
+	 */
+	def findOptimalTriggerSequence(DirectedMultigraph<CosimUnitInstance, DefaultWeightedEdge> graph) {
+		// TODO
+	}
+	
 	/*
 	 * This method will perform roughly the following steps:
 	 * 1. Transform the scenario (assumed to be non-hierarchical) into a graph where each node represents a cosim unit, and each connection between cosim units represents the cost of executing the latter after executing the former.
@@ -70,4 +95,10 @@ class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 		
 	}
 	
+}
+
+class BasicHeuristic implements AStarAdmissibleHeuristic<LazySearchNode> {
+	override getCostEstimate(LazySearchNode sourceVertex, LazySearchNode targetVertex) {
+		0.0 // TODO Better heuristics might be to get the min weight of possible edges
+	}
 }

+ 127 - 0
HintCOEngine/src/ua/ansymo/hintco/LazySearchTree.xtend

@@ -0,0 +1,127 @@
+package ua.ansymo.hintco
+
+import org.eclipse.core.runtime.Assert
+import org.jgrapht.graph.DefaultWeightedEdge
+import org.jgrapht.graph.DirectedMultigraph
+import org.jgrapht.graph.SimpleDirectedWeightedGraph
+import org.jgrapht.util.SupplierUtil
+import org.eclipse.xtend.lib.annotations.Accessors
+
+/*
+ * Represents the search space used in the algebraic loop optimizer. Lazily expands the graph as the search algorithm works it's way towards the optimal solution.
+ */
+class LazySearchTree extends SimpleDirectedWeightedGraph<LazySearchNode, DefaultWeightedEdge> {
+	
+	DirectedMultigraph<CosimUnitInstance, DefaultWeightedEdge> triggerGraph
+	
+	@Accessors(PUBLIC_GETTER, NONE) EmptyTriggerSequence root = new EmptyTriggerSequence
+	@Accessors(PUBLIC_GETTER, NONE) CompleteTriggerSequence bottom = new CompleteTriggerSequence
+	
+	
+	new(DirectedMultigraph<CosimUnitInstance, DefaultWeightedEdge> tg) {
+		super(SupplierUtil.createSupplier(LazySearchNode), SupplierUtil.createSupplier(DefaultWeightedEdge))
+		Assert.isTrue(!tg.vertexSet.empty)
+		triggerGraph = tg
+		// Define the default start and end nodes.
+		this.addVertex(root)
+		this.addVertex(bottom)
+	}
+	
+	/*
+	 * Computes the edges and vertices that are outgoing from vertex, and adds them to the graph.
+	 * It considers three kinds of LazySearchNode: the EmptyTriggerSequence, the PartialTriggerSequence, and the CompleteTriggerSequence.
+	 * In the case of EmptyTriggerSequence, then the successors are all possible vertices on the graph.
+	 * In the case of PartialTriggerSequence, then the successors are all possible vertices on the graph, except for those that are already part of the trigger sequence (this is naive, see below).
+	 * In the case of CompleteTriggerSequence, then there are no successors, and an exception should be thrown.
+	 * I think it is possible to reduce the successors in the case of a PartialTriggerSequence. Essentially, one would expect the optimal trigger sequence to be a path in the triggerGraph. 
+	 * This is because whenever we pick a cosim unit A, any cosim units that depend on A have their cost reduced, so it would make sense that the optimal choice will be among them. 
+	 * However, for cosim scenarios that results in non strongly connected graphs, one may be forced to chose a successor which is not a successor of A in triggerGraph.
+	 * Therefore I'm going for the most naive approach to just enum all, and let A* select the best choice.
+	 */
+	override outgoingEdgesOf(LazySearchNode vertex) {
+		if (vertex instanceof EmptyTriggerSequence) {
+			Assert.isTrue(vertex.inDegreeOf == 0, "This vertex should be the root of the search tree.")
+			for (v : triggerGraph.vertexSet) {
+				createNewEdge(vertex, v)
+			}
+		} else if (vertex instanceof CompleteTriggerSequence) {
+			throw new IllegalArgumentException()
+		} else if (vertex instanceof PartialTriggerSequence) {
+			val potentialSuccessors = triggerGraph.vertexSet.filter[v | !recIsAncestorOf(v, vertex)]
+			if (potentialSuccessors.empty) {
+				val edge = this.addEdge(vertex, bottom)
+				Assert.isNotNull(edge) // Otherwise, this vertex has been expanded before, the solution found, and then the search problem got back here.
+				this.setEdgeWeight(edge, 0.0) // No cost for the edge that reaches bottom
+			} else {
+				for (v : potentialSuccessors) {
+					createNewEdge(vertex, v)
+				}
+			}
+			
+		}
+		return super.outgoingEdgesOf(vertex)
+	}
+	
+	private def createNewEdge(LazySearchNode vertex, CosimUnitInstance v) {
+		val newV = new PartialTriggerSequence(v)
+		val newEdge = this.addEdge(vertex, newV)
+		this.setEdgeWeight(newEdge, costOfEdge(newV))
+	}
+	
+	def boolean recIsAncestorOf(CosimUnitInstance ancestorUnit, PartialTriggerSequence vertex) {
+		// Base case
+		val predecessors = vertex.incomingEdgesOf
+		Assert.isTrue(!predecessors.empty)
+		if (predecessors.size == 1) {
+			Assert.isTrue(predecessors.head.edgeSource instanceof EmptyTriggerSequence)
+			return false
+		}
+		for (p : predecessors) {
+			val partialP = p.edgeSource as PartialTriggerSequence
+			if (partialP.unit == ancestorUnit) {
+				return true
+			}
+			if (recIsAncestorOf(ancestorUnit, partialP)){
+				return true
+			}
+		}
+		return false
+	}
+	
+	/*
+	 * Defines the cost of an edge A->B. 
+	 * This is given by the sum of the weights of incoming connections to B (in the triggerGraph) that are not ancestors of B in the search tree.
+	 */
+	def costOfEdge(PartialTriggerSequence B){
+		val Bunit = B.unit
+		val incommingEdges = triggerGraph.incomingEdgesOf(Bunit).filter[inc | recIsAncestorOf(triggerGraph.getEdgeSource(inc), B)]
+		val cost = incommingEdges.map[edge|triggerGraph.getEdgeWeight(edge)].reduce[p1, p2|p1+p2]
+		return cost
+	}
+}
+
+abstract class LazySearchNode {
+	
+}
+
+/*
+ * Represents a partial trigger sequence of a graph.
+ * 
+ */
+class PartialTriggerSequence extends LazySearchNode {
+	@Accessors(PUBLIC_GETTER, PROTECTED_SETTER) CosimUnitInstance unit
+	new (CosimUnitInstance u){
+		unit = u	
+	}
+	override toString() {
+		unit.toString
+	}
+}
+
+/*
+ * The following two classes are used to identify the start and end of the search
+ */
+class EmptyTriggerSequence extends LazySearchNode {}
+class CompleteTriggerSequence extends LazySearchNode {}
+
+

+ 1 - 2
HintCOEngine/test/ua/ansymo/hintco/test/AlgebraicLoopVariantProcessorTest.xtend

@@ -10,8 +10,7 @@ import ua.ansymo.hintco.ModelStorage
 
 import static org.junit.Assert.*
 
-// TODO Rename this to AlgebraicLoopProcessingTest
-class AlgebraicLoopVariantProcessorTest {
+class AlgebraicLoopProcessingTests {
 	
 	@Test
 	def void addConstraintsWithAlgebraicLoopsTest() {

+ 204 - 0
HintConfiguration.edit/src/ua/ansymo/hintco/provider/PrecedenceNodeItemProvider.java

@@ -0,0 +1,204 @@
+/**
+ */
+package ua.ansymo.hintco.provider;
+
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.Notification;
+
+import org.eclipse.emf.common.util.ResourceLocator;
+
+import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.IEditingDomainItemProvider;
+import org.eclipse.emf.edit.provider.IItemLabelProvider;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.IItemPropertySource;
+import org.eclipse.emf.edit.provider.IStructuredItemContentProvider;
+import org.eclipse.emf.edit.provider.ITreeItemContentProvider;
+import org.eclipse.emf.edit.provider.ItemProviderAdapter;
+
+import ua.ansymo.hintco.HintcoPackage;
+
+/**
+ * This is the item provider adapter for a {@link ua.ansymo.hintco.PrecedenceNode} object.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+public class PrecedenceNodeItemProvider 
+	extends ItemProviderAdapter
+	implements
+		IEditingDomainItemProvider,
+		IStructuredItemContentProvider,
+		ITreeItemContentProvider,
+		IItemLabelProvider,
+		IItemPropertySource {
+	/**
+	 * This constructs an instance from a factory and a notifier.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	public PrecedenceNodeItemProvider(AdapterFactory adapterFactory) {
+		super(adapterFactory);
+	}
+
+	/**
+	 * This returns the property descriptors for the adapted class.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object) {
+		if (itemPropertyDescriptors == null) {
+			super.getPropertyDescriptors(object);
+
+			addPrecedesPropertyDescriptor(object);
+			addSucceedsPropertyDescriptor(object);
+			addBeforePropertyDescriptor(object);
+			addAfterPropertyDescriptor(object);
+		}
+		return itemPropertyDescriptors;
+	}
+
+	/**
+	 * This adds a property descriptor for the Precedes feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addPrecedesPropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecedenceNode_precedes_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecedenceNode_precedes_feature", "_UI_PrecedenceNode_type"),
+				 HintcoPackage.Literals.PRECEDENCE_NODE__PRECEDES,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
+	/**
+	 * This adds a property descriptor for the Succeeds feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addSucceedsPropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecedenceNode_succeeds_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecedenceNode_succeeds_feature", "_UI_PrecedenceNode_type"),
+				 HintcoPackage.Literals.PRECEDENCE_NODE__SUCCEEDS,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
+	/**
+	 * This adds a property descriptor for the Before feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addBeforePropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecedenceNode_before_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecedenceNode_before_feature", "_UI_PrecedenceNode_type"),
+				 HintcoPackage.Literals.PRECEDENCE_NODE__BEFORE,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
+	/**
+	 * This adds a property descriptor for the After feature.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	protected void addAfterPropertyDescriptor(Object object) {
+		itemPropertyDescriptors.add
+			(createItemPropertyDescriptor
+				(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+				 getResourceLocator(),
+				 getString("_UI_PrecedenceNode_after_feature"),
+				 getString("_UI_PropertyDescriptor_description", "_UI_PrecedenceNode_after_feature", "_UI_PrecedenceNode_type"),
+				 HintcoPackage.Literals.PRECEDENCE_NODE__AFTER,
+				 true,
+				 false,
+				 true,
+				 null,
+				 null,
+				 null));
+	}
+
+	/**
+	 * This returns the label text for the adapted class.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public String getText(Object object) {
+		return getString("_UI_PrecedenceNode_type");
+	}
+
+
+	/**
+	 * This handles model notifications by calling {@link #updateChildren} to update any cached
+	 * children and by creating a viewer notification, which it passes to {@link #fireNotifyChanged}.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public void notifyChanged(Notification notification) {
+		updateChildren(notification);
+		super.notifyChanged(notification);
+	}
+
+	/**
+	 * This adds {@link org.eclipse.emf.edit.command.CommandParameter}s describing the children
+	 * that can be created under this object.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	protected void collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) {
+		super.collectNewChildDescriptors(newChildDescriptors, object);
+	}
+
+	/**
+	 * Return the resource locator for this item provider's resources.
+	 * <!-- begin-user-doc -->
+	 * <!-- end-user-doc -->
+	 * @generated
+	 */
+	@Override
+	public ResourceLocator getResourceLocator() {
+		return HintConfigurationEditPlugin.INSTANCE;
+	}
+
+}