blob: 4c06381bac688b5450ebb4db4d6da80bebd7fae1 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2016 CEA LIST.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* CEA LIST Initial API and implementation
*****************************************************************************/
package org.eclipse.papyrus.moka.fmi.master.masterlibrary;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.eclipse.papyrus.moka.fmi.master.fmilibrary.Fmi2Port;
import org.eclipse.uml2.uml.Dependency;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.internal.impl.PropertyImpl;
/**
* A directed graph composed of nodes (the inputs and outputs ports of the cosimulation graph)
* and edges (I/O dependency relations and O/I connections of the cosimulation graph)
*/
public class DependencyGraph {
private ArrayList<Edge> edges = new ArrayList<Edge>();
private ArrayList<Node> nodes = new ArrayList<Node>();
private boolean cyclic = false;
/**
* creates the dependency graph from the coSimgraph
**/
public DependencyGraph(CoSimEnvironment cosimEnvironnement) {
List<Dependency> ioDependencies = cosimEnvironnement.getIoDependencies();
// create the edges of the dependency graph
// Port mapping --> Output 2 Input
// Dependencies --> Input 2 Output
Node sourceNode = null;
Node targetNode = null;
for (Fmi2Port targetPort : cosimEnvironnement.getInputPorts()) {
Fmi2Port sourcePort = targetPort.getDrivingPort();
// create an edge from the output to the input
// this correspond to create an edge from value to key
// the key is an input port --> target
// the value is an output port --> source
sourceNode = new Node(sourcePort);
targetNode = new Node(targetPort);
Edge edge = new Edge(sourceNode, targetNode);
this.addNode(sourceNode);
this.addNode(targetNode);
this.addEdge(edge);
}
for (Dependency d : ioDependencies) {
if ((d.getClients().get(0)) instanceof Port) {
Port client = (Port) d.getClients().get(0); // an output port --> target node,
if (d.getSuppliers().get(0) instanceof Port) {
Port supplier = (Port) d.getSuppliers().get(0); // an input port --> source node
for (Node n : this.getNodes()) {
if ((n.getVariable().getPort()).equals(client)) {
targetNode = n;
}
if ((n.getVariable().getPort()).equals(supplier)) {
sourceNode = n;
}
}
Edge edge = new Edge(sourceNode, targetNode);
this.addEdge(edge);
}
}
}
}
public ArrayList<Fmi2Port> topoSort() {
/**
* L ← Empty list that will contain the sorted elements
* S ← Set of all nodes with no incoming edges
* while S is non-empty do
* remove a node n from S
* add n to tail of L
* for each node m with an edge e from n to m do
* remove edge e from the graph
* if m has no other incoming edges then
* insert m into S
* if graph has edges then
* return error (graph has at least one cycle)
* else
* return L (a topologically sorted order)
**/
boolean moreEdges = true;
DependencyGraph G = this;
ArrayList<Fmi2Port> L = new ArrayList<Fmi2Port>();// L ← Empty list that will contain the sorted elements
ArrayList<Node> S = new ArrayList<Node>(); // S ← Set of all nodes with no incoming edges
for (Node n : G.nodes) {
if (n.getIncomings().size() == 0) {
S.add(n);
}
}
while (S.size() > 0) { // while S is non-empty do
moreEdges = true;
Node n = S.get(0);
S.remove(0); // remove n from S
L.add(n.getVariable()); // add n to tail of L
ArrayList<Edge> n2m = n.getOutgoings();
if (n2m.size() > 0) {
while (moreEdges) {
Node m = n2m.get(0).getTarget();
removeEdge(n2m.get(0), G);
if (m.getIncomings().size() == 0) {
S.add(m);
}
if (n2m.size() > 0) {
n2m.remove(0);
}
if (n2m.size() == 0) {
moreEdges = false;
}
}
}
}
if (G.edges.size() > 0) {
this.cyclic = true;
System.out.println("the graph is cyclic, cannot continue cosimulation");
}
return L;
}
public void addNode(Node node) {
// TODO Auto-generated method stub
nodes.add(node);
}
public void addEdge(Edge edge) {
// TODO Auto-generated method stub
edges.add(edge);
edge.getSource().getOutgoings().add(edge);
edge.getTarget().getIncomings().add(edge);
}
public void removeEdge(Edge edge, DependencyGraph g) {
// TODO Auto-generated method stub
int index = g.edges.indexOf(edge);
if (index != -1) {
int source_index = edge.getSource().getOutgoings().indexOf(edge);
if (source_index != -1) {
edge.getSource().getOutgoings().remove(source_index);
}
int target_index = edge.getTarget().getIncomings().indexOf(edge);
if (target_index != -1) {
edge.getTarget().getIncomings().remove(target_index);
}
g.edges.remove(index);
} else {
System.out.println("error, edge not found!!");
}
}
public ArrayList<Edge> getEdges() {
return edges;
}
public void setEdges(ArrayList<Edge> edges) {
this.edges = edges;
}
public ArrayList<Node> getNodes() {
return nodes;
}
public void setNodes(ArrayList<Node> nodes) {
this.nodes = nodes;
}
public boolean isCyclic() {
return cyclic;
}
public void setCyclic(boolean cyclic) {
this.cyclic = cyclic;
}
}