| /***************************************************************************** |
| * 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) ; |
| } |
| |
| } |