blob: 02ec8ec8cfe0d3982cd89d7e18716e200cd9b094 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2017 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.parametric.semantics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.papyrus.moka.fuml.structuredclassifiers.IObject_;
import org.eclipse.papyrus.moka.parametric.utils.Graph;
import org.eclipse.uml2.uml.ConnectorEnd;
import org.eclipse.uml2.uml.Property;
public class EvaluationGraph {
protected IEvaluable context ;
protected Map<ConstraintObject, Set<ConstraintObject>> graphDependencies = new HashMap<ConstraintObject, Set<ConstraintObject>>() ;
protected Set<ConstraintObject> allConstraintObjects = new HashSet<ConstraintObject>() ;
protected Map<ConstraintObject, List<UpdateDescriptor>> preEvaluateUpdatesMap = new HashMap<ConstraintObject, List<UpdateDescriptor>>() ;
protected Map<ConstraintObject, List<UpdateDescriptor>> postEvaluateUpdatesMap = new HashMap<ConstraintObject, List<UpdateDescriptor>>() ;
private List<ConstraintObject> sorted;
public EvaluationGraph(IEvaluable context) {
this.context = context;
// TODO compute predecessors and successors maps from binding links
for (BindingLink b : context.getBindingLinks()) {
ConnectorEnd end1 = b.bindingConnector.getEnds().get(0) ;
ConnectorEnd end2 = b.bindingConnector.getEnds().get(1) ;
IObject_ obj1 = b.getFirstObjectFromPropertyPath(end1) ;
IObject_ obj2 = b.getFirstObjectFromPropertyPath(end2) ;
if (isConstraintObject(obj1) && !isConstraintObject(obj2)) {
allConstraintObjects.add((ConstraintObject)obj1) ;
// Check if end1.role is an input parameter on obj1,
// in order to perform propagation from end2 to end1 if needed
if (((ConstraintObject)obj1).isInputParam((Property)end1.getRole())) {
UpdateDescriptor updateDescriptor = new UpdateDescriptor(b, end2, end1) ;
List<UpdateDescriptor> updates = this.preEvaluateUpdatesMap.get(obj1) ;
if (updates == null) {
updates = new ArrayList<UpdateDescriptor>() ;
this.preEvaluateUpdatesMap.put((ConstraintObject)obj1, updates) ;
}
updates.add(updateDescriptor) ;
}
else {
UpdateDescriptor updateDescriptor = new UpdateDescriptor(b, end1, end2) ;
List<UpdateDescriptor> updates = this.postEvaluateUpdatesMap.get(obj1) ;
if (updates == null) {
updates = new ArrayList<UpdateDescriptor>() ;
this.postEvaluateUpdatesMap.put((ConstraintObject)obj1, updates) ;
}
updates.add(updateDescriptor) ;
}
}
else if (!isConstraintObject(obj1) && isConstraintObject(obj2)) {
allConstraintObjects.add((ConstraintObject)obj2) ;
// Check if end2.role is an output parameter on obj2,
// in order to perform propagation from end1 to end2 if needed
if (((ConstraintObject)obj2).isInputParam((Property)end2.getRole())) {
UpdateDescriptor updateDescriptor = new UpdateDescriptor(b, end1, end2) ;
List<UpdateDescriptor> updates = this.preEvaluateUpdatesMap.get(obj2) ;
if (updates == null) {
updates = new ArrayList<UpdateDescriptor>() ;
this.preEvaluateUpdatesMap.put((ConstraintObject)obj2, updates) ;
}
updates.add(updateDescriptor) ;
}
else {
UpdateDescriptor updateDescriptor = new UpdateDescriptor(b, end2, end1) ;
List<UpdateDescriptor> updates = this.postEvaluateUpdatesMap.get(obj2) ;
if (updates == null) {
updates = new ArrayList<UpdateDescriptor>() ;
this.postEvaluateUpdatesMap.put((ConstraintObject)obj2, updates) ;
}
updates.add(updateDescriptor) ;
}
}
else if (isConstraintObject(obj1) && isConstraintObject(obj2)) {
allConstraintObjects.add((ConstraintObject)obj1) ;
allConstraintObjects.add((ConstraintObject)obj2) ;
// Compute dependencies the causality graph
boolean end1IsAnInputParam = ((ConstraintObject)obj1).isInputParam((Property)end1.getRole()) ;
boolean end2isAnInputParam = ((ConstraintObject)obj2).isInputParam((Property)end2.getRole()) ;
if (end1IsAnInputParam && end2isAnInputParam) {
// Input connected on Input. => The model is illformed. Don't do anything
}
else if (!end1IsAnInputParam && !end2isAnInputParam) {
// Output connected on Output. => The model is illformed. Don't do anything
}
else if (end1IsAnInputParam) {
addDependency((ConstraintObject)obj2, (ConstraintObject)obj1);
UpdateDescriptor updateDescriptor = new UpdateDescriptor(b, end2, end1) ;
List<UpdateDescriptor> updates = this.postEvaluateUpdatesMap.get(obj2) ;
if (updates == null) {
updates = new ArrayList<UpdateDescriptor>() ;
this.postEvaluateUpdatesMap.put((ConstraintObject)obj2, updates) ;
}
updates.add(updateDescriptor) ;
}
else if (end2isAnInputParam) {
addDependency((ConstraintObject)obj1, (ConstraintObject)obj2);
UpdateDescriptor updateDescriptor = new UpdateDescriptor(b, end1, end2) ;
List<UpdateDescriptor> updates = this.postEvaluateUpdatesMap.get(obj1) ;
if (updates == null) {
updates = new ArrayList<UpdateDescriptor>() ;
this.postEvaluateUpdatesMap.put((ConstraintObject)obj1, updates) ;
}
updates.add(updateDescriptor) ;
}
}
}
}
public void evaluate() {
// build the graph,
if (sorted == null) {
Graph<ConstraintObject> g = new Graph<ConstraintObject>(allConstraintObjects, graphDependencies) ;
// do a topological sort
sorted = g.topologicalSort();
}
// execute computations in corresponding order
for (ConstraintObject obj : sorted) {
List<UpdateDescriptor> preUpdates = this.preEvaluateUpdatesMap.get(obj) ;
if (preUpdates != null) {
for (UpdateDescriptor update : preUpdates) {
update.performUpdate() ;
}
}
obj.evaluate();
List<UpdateDescriptor> updates = this.postEvaluateUpdatesMap.get(obj) ;
if (updates != null) {
for (UpdateDescriptor update : updates) {
update.performUpdate() ;
}
}
}
}
public boolean isConstraintObject(IObject_ obj) {
return obj != null && obj instanceof ConstraintObject ;
}
public void addDependency(ConstraintObject from, ConstraintObject to) {
Set<ConstraintObject> dependencies = graphDependencies.get(from) ;
if (dependencies == null) {
dependencies = new HashSet<ConstraintObject>() ;
graphDependencies.put(from, dependencies) ;
}
dependencies.add(to) ;
}
}