blob: 047d6861887f15ca165be0e6827cb65c9e52a343 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.Nameable;
import org.eclipse.qvtd.compiler.CompilerProblem;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.RegionsAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.ScheduleManager;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.TransformationAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtm2qvts.QVTm2QVTs;
import org.eclipse.qvtd.compiler.internal.qvtr2qvtc.QVTrNameGenerator;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.RegionAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.utilities.ReachabilityForest;
import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.DispatchRegion;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.MappingRegion;
import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge;
import org.eclipse.qvtd.pivot.qvtschedule.Node;
import org.eclipse.qvtd.pivot.qvtschedule.Region;
import org.eclipse.qvtd.pivot.qvtschedule.Role;
import org.eclipse.qvtd.pivot.qvtschedule.SuccessEdge;
import org.eclipse.qvtd.pivot.qvtschedule.VerdictRegion;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* The MappingPartitioner supervises the partitioning of a mapping region into a 'tree' of partitions that avoid
* scheduling hazards. Each partition describes the future content of a micromapping. For non-degerate cases the 'tree'
* comprises a sequence of Speculation, Speculating, Speculated partitions followed by zero or more concurrent Edge partitions.
*
* The Speculation partition establishes the basic pattern of inputs objects that justify creation of a speculated trace object.
*
* The Speculating partition interacts with other Speculations to establish that all predicates are satisfied.
*
* The Speculated partition creates the immediate corollaries of the successful speculation.
*
* The Edge partitions realize further edges once their targets are available.
*
* Each MappingPartitioner collaborates with an overall TransformationPartitioner for global analyses.
*/
public class MappingPartitioner implements Nameable
{
protected final @NonNull ScheduleManager scheduleManager;
/**
* The overall transformation partitioner providing global analysis results.
*/
protected final @NonNull RegionsAnalysis<@NonNull Partition> regionsPartitionAnalysis;
/**
* The overall transformation analysis results.
*/
protected final @NonNull TransformationAnalysis transformationAnalysis;
/**
* The region to be partitioned.
*/
protected final @NonNull RegionAnalysis regionAnalysis;
/**
* The region to be partitioned.
*/
protected final @NonNull MappingRegion region;
/**
* Dynamically growing list of constant edges that have been traversed by a partition.
*/
private final @NonNull Set<@NonNull Edge> alreadyConstantEdges = new HashSet<>();
/**
* Dynamically growing list of loaded edges that have been traversed by a partition.
*/
private final @NonNull Set<@NonNull Edge> alreadyLoadedEdges = new HashSet<>();
/**
* Dynamically growing list of edges that have been predicated by a partition.
*/
private final @NonNull Set<@NonNull Edge> alreadyPredicatedEdges = new HashSet<>();
/**
* Dynamically growing list of nodes that have been predicated by a partition.
*/
private final @NonNull Set<@NonNull Node> alreadyPredicatedNodes = new HashSet<>();
/**
* Dynamically growing map of edges that have been realized to the partition that realizes them.
*/
private final @NonNull Map<@NonNull Edge, @NonNull AbstractPartialPartition> alreadyRealizedEdges = new HashMap<>();
/**
* Dynamically growing list of nodes that have been realized by a partition.
*/
private final @NonNull Set<@NonNull Node> alreadyRealizedNodes = new HashSet<>();
private final @NonNull Map<@NonNull Edge, @NonNull List<@NonNull AbstractPartialPartition>> debugEdge2partitions = new HashMap<>();
public MappingPartitioner(@NonNull TransformationPartitioner transformationPartitioner, @NonNull RegionAnalysis regionAnalysis) {
this.scheduleManager = transformationPartitioner.getScheduleManager();
this.regionsPartitionAnalysis = transformationPartitioner;
this.transformationAnalysis = transformationPartitioner.getTransformationAnalysis();
this.regionAnalysis = regionAnalysis;
this.region = (MappingRegion) regionAnalysis.getRegion();
//
}
public void addEdge(@NonNull Edge edge, @NonNull Role newEdgeRole, @NonNull AbstractPartialPartition partition) {
if (newEdgeRole == Role.CONSTANT) {
alreadyConstantEdges.add(edge);
}
else if (newEdgeRole == Role.LOADED) {
alreadyLoadedEdges.add(edge);
}
else if (newEdgeRole == Role.PREDICATED) {
alreadyPredicatedEdges.add(edge);
}
else if (newEdgeRole == Role.SPECULATED) {
alreadyPredicatedEdges.add(edge);
}
else if (newEdgeRole == Role.REALIZED) {
alreadyRealizedEdges.put(edge, partition);
}
List<@NonNull AbstractPartialPartition> partitions = debugEdge2partitions.get(edge);
if (partitions == null) {
partitions = new ArrayList<>();
debugEdge2partitions.put(edge, partitions);
}
assert !partitions.contains(partition);
partitions.add(partition);
}
public boolean addPredicatedNode(@NonNull Node node) {
return alreadyPredicatedNodes.add(node);
}
public void addProblem(@NonNull CompilerProblem problem) {
scheduleManager.addProblem(problem);
}
public boolean addRealizedNode(@NonNull Node node) {
return alreadyRealizedNodes.add(node);
}
public @Nullable Node basicGetDispatchNode() {
return regionAnalysis.basicGetDispatchNode();
}
public @Nullable SuccessEdge basicGetGlobalSuccessEdge(@NonNull Node traceNode) {
return regionAnalysis.basicGetGlobalSuccessEdge(traceNode);
}
public @Nullable Node basicGetGlobalSuccessNode(@NonNull Node traceNode) {
return regionAnalysis.basicGetGlobalSuccessNode(traceNode);
}
public @Nullable SuccessEdge basicGetLocalSuccessEdge(@NonNull Node traceNode) {
return regionAnalysis.basicGetLocalSuccessEdge(traceNode);
}
public @Nullable Node basicGetLocalSuccessNode(@NonNull Node traceNode) {
return regionAnalysis.basicGetLocalSuccessNode(traceNode);
}
private void check(/*boolean isInfallible*/) {
/* Set<@NonNull Edge> infallibleEdges = null;
Set<@NonNull Node> infallibleNodes = null;
if (isInfallible) {
infallibleEdges = new HashSet<>();
infallibleNodes = new HashSet<>();
for (@NonNull Edge edge : regionAnalysis.getFallibleEdges()) {
infallibleEdges.add(edge);
infallibleNodes.add(QVTscheduleUtil.getTargetNode(edge));
}
} */
for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) {
if (((node.isSpeculated() && !node.isHead()) || node.isRealized()) && !hasRealizedNode(node)) {
// if ((infallibleNodes == null) || !infallibleNodes.contains(node)) {
addProblem(CompilerUtil.createRegionError(region, "Should have realized " + node));
// }
}
}
Set<@NonNull Edge> allPrimaryEdges = new HashSet<>();
for (@NonNull Edge edge : QVTscheduleUtil.getOwnedEdges(region)) {
if (!edge.isSecondary()) {
allPrimaryEdges.add(edge);
if (edge.isRealized() && !hasRealizedEdge(edge) && !edge.isExpression()) {
// if ((infallibleEdges == null) || !infallibleEdges.contains(edge)) {
addProblem(CompilerUtil.createRegionError(region, "Should have realized " + edge));
// }
}
}
}
//
Set<@NonNull Node> deadNodes = computeDeadNodes(QVTscheduleUtil.getOwnedNodes(region));
Set<@NonNull Edge> deadEdges = computeDeadEdges(deadNodes);
allPrimaryEdges.removeAll(deadEdges);
Set<@NonNull Edge> partitionedEdges = new HashSet<>(debugEdge2partitions.keySet());
if (!partitionedEdges.equals(allPrimaryEdges)) {
Set<@NonNull Edge> extraEdgesSet = Sets.newHashSet(partitionedEdges);
CompilerUtil.removeAll(extraEdgesSet, allPrimaryEdges);
for (@NonNull Edge edge : extraEdgesSet) {
if (!edge.isSecondary()) {
@SuppressWarnings("unused")
List<@NonNull AbstractPartialPartition> extraPartitions = debugEdge2partitions.get(edge);
addProblem(CompilerUtil.createRegionWarning(region, "Extra " + edge));
}
}
Set<@NonNull Edge> missingEdgesSet = Sets.newHashSet(allPrimaryEdges);
missingEdgesSet.removeAll(partitionedEdges);
for (@NonNull Edge edge : missingEdgesSet) {
if (!(edge instanceof NavigableEdge) || (transformationAnalysis.getCorollaryOf((NavigableEdge)edge) == null)) {// && !isDead(edge)) {
addProblem(CompilerUtil.createRegionWarning(region, "Missing " + edge));
}
}
}
}
private @NonNull Set<@NonNull Edge> computeDeadEdges(@NonNull Iterable<@NonNull Node> deadNodes) {
Set<@NonNull Edge> deadEdges = new HashSet<>();
for (@NonNull Node node : deadNodes) {
Iterables.addAll(deadEdges, QVTscheduleUtil.getIncomingEdges(node));
Iterables.addAll(deadEdges, QVTscheduleUtil.getOutgoingEdges(node));
}
return deadEdges;
}
private @NonNull Set<@NonNull Node> computeDeadNodes(@NonNull Iterable<@NonNull Node> nodes) {
Set<@NonNull Node> deadNodes = new HashSet<>();
Set<@NonNull Node> moreDeadNodes = null;
for (@NonNull Node node : nodes) {
if (!node.isHead() && isDead(node, null)) {
if (moreDeadNodes == null) {
moreDeadNodes = new HashSet<>();
}
moreDeadNodes.add(node);
}
}
if (moreDeadNodes == null) {
return deadNodes;
}
while (moreDeadNodes.size() > 0) {
deadNodes.addAll(moreDeadNodes);
List<@NonNull Node> moreDeadNodesList = new ArrayList<>(moreDeadNodes);
moreDeadNodes = null;
for (@NonNull Node deadNode : moreDeadNodesList) {
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(deadNode)) {
Node sourceNode = edge.getEdgeSource();
if (!sourceNode.isHead() && isDead(sourceNode, deadNodes)) {
if (moreDeadNodes == null) {
moreDeadNodes = new HashSet<>();
}
moreDeadNodes.add(sourceNode);
}
}
}
if (moreDeadNodes == null) {
break;
}
}
return deadNodes;
}
private @NonNull ActivatorPartition createActivatorPartition() {
ReachabilityForest reachabilityForest = new ReachabilityForest(getReachabilityRootNodes(), getAvailableNavigableEdges());
return new ActivatorPartition(this, reachabilityForest);
}
private @NonNull AssignmentPartition createAssignmentPartition(@NonNull ReachabilityForest reachabilityForest, @NonNull Edge outputEdge) {
return new AssignmentPartition(this, reachabilityForest, outputEdge);
}
private @NonNull NonPartition createNonPartition() {
return new NonPartition(this);
}
private @NonNull ResidualPartition createResidualPartition() {
ReachabilityForest reachabilityForest = new ReachabilityForest(getReachabilityRootNodes(), getAvailableNavigableEdges());
return new ResidualPartition(this, reachabilityForest);
}
private @NonNull SpeculatedPartition createSpeculatedPartition() {
ReachabilityForest reachabilityForest = new ReachabilityForest(getReachabilityRootNodes(), getAvailableNavigableEdges());
return new SpeculatedPartition(this, reachabilityForest);
}
private @NonNull SpeculatingPartition createSpeculatingPartition(/*boolean isInfallible*/) {
ReachabilityForest reachabilityForest = new ReachabilityForest(getReachabilityRootNodes(), getAvailableNavigableEdges());
return new SpeculatingPartition(this, reachabilityForest/*, isInfallible*/);
}
private @NonNull SpeculationPartition createSpeculationPartition() {
ReachabilityForest reachabilityForest = new ReachabilityForest(getSpeculationReachabilityRootNodes(), getAvailableNavigableEdges());
return new SpeculationPartition(this, reachabilityForest);
}
// public @NonNull Iterable<@NonNull Edge> getAlreadyPredicatedEdges() {
// return alreadyPredicatedEdges;
// }
public @NonNull Iterable<@NonNull Edge> getAlreadyRealizedEdges() {
return alreadyRealizedEdges.keySet();
}
/**
* Return the navigable edges that may be used by to locate nodes by this partition.
* The default implementation returns all old primary navigable edges
* and all already realized navigable edges
*/
private @NonNull Iterable<@NonNull NavigableEdge> getAvailableNavigableEdges() {
List<@NonNull NavigableEdge> navigableEdges = Lists.newArrayList(getOldPrimaryNavigableEdges());
for (@NonNull Edge edge : getAlreadyRealizedEdges()) {
if (edge instanceof NavigableEdge) {
navigableEdges.add((NavigableEdge) edge);
}
}
return navigableEdges;
}
public @NonNull Iterable<@NonNull Node> getConstantInputNodes() {
return regionAnalysis.getConstantInputNodes();
}
public @NonNull Iterable<@NonNull Node> getConstantOutputNodes() {
return regionAnalysis.getConstantOutputNodes();
}
public @Nullable Iterable<@NonNull TraceClassAnalysis<@NonNull RegionAnalysis>> getConsumedTraceClassAnalyses() {
return regionAnalysis.getConsumedTraceClassAnalyses();
}
public @Nullable Iterable<@NonNull TracePropertyAnalysis<@NonNull RegionAnalysis>> getConsumedTracePropertyAnalyses() {
return regionAnalysis.getConsumedTracePropertyAnalyses();
}
public @NonNull Iterable<@NonNull Node> getExecutionNodes() {
return Iterables.concat(getPredicatedExecutionNodes(), getRealizedExecutionNodes());
}
public @NonNull SuccessEdge getGlobalSuccessEdge(@NonNull Node traceNode) {
return regionAnalysis.getGlobalSuccessEdge(traceNode);
}
public @NonNull Node getGlobalSuccessNode(@NonNull Node traceNode) {
return regionAnalysis.getGlobalSuccessNode(traceNode);
}
public @NonNull SuccessEdge getLocalSuccessEdge(@NonNull Node traceNode) {
return regionAnalysis.getLocalSuccessEdge(traceNode);
}
public @NonNull Node getLocalSuccessNode(@NonNull Node traceNode) {
return regionAnalysis.getLocalSuccessNode(traceNode);
}
@Override
public String getName() {
return region.getName();
}
public @NonNull Iterable<@NonNull NavigableEdge> getOldPrimaryNavigableEdges() {
return regionAnalysis.getOldPrimaryNavigableEdges();
}
public @NonNull Iterable<@NonNull Edge> getPredicatedEdges() {
return regionAnalysis.getPredicatedEdges();
}
public @NonNull List<@NonNull Node> getPredicatedExecutionNodes() {
List<@NonNull Node> predicatedExecutionNodes = new ArrayList<>();
for (@NonNull Node node : getPredicatedMiddleNodes()) {
if (QVTrNameGenerator.TRACECLASS_PROPERTY_NAME.equals(node.getName())) {
assert node.isTrace();
predicatedExecutionNodes.add(node);
}
}
return predicatedExecutionNodes;
}
public @NonNull Iterable<@NonNull Node> getPredicatedMiddleNodes() {
return regionAnalysis.getPredicatedMiddleNodes();
}
public @NonNull Iterable<@NonNull Node> getPredicatedOutputNodes() {
return regionAnalysis.getPredicatedOutputNodes();
}
public @NonNull List<@NonNull Node> getPredicatedWhenNodes() {
List<@NonNull Node> predicatedWhenNodes = new ArrayList<>();
for (@NonNull Node node : getPredicatedMiddleNodes()) {
if (node.getName().startsWith("when_")) {
predicatedWhenNodes.add(node);
}
}
return predicatedWhenNodes;
}
public @Nullable Iterable<@NonNull TraceClassAnalysis<@NonNull RegionAnalysis>> getProducedTraceClassAnalyses() {
return regionAnalysis.getProducedTraceClassAnalyses();
}
public @Nullable Iterable<@NonNull TracePropertyAnalysis<@NonNull RegionAnalysis>> getProducedTracePropertyAnalyses() {
return regionAnalysis.getProducedTracePropertyAnalyses();
}
private @NonNull Iterable<@NonNull Node> getReachabilityRootNodes() {
Iterable<@NonNull Node> traceNodes = getTraceNodes();
Iterable<@NonNull Node> constantInputNodes = getConstantInputNodes();
return Iterables.concat(traceNodes, constantInputNodes);
}
public @NonNull Iterable<@NonNull NavigableEdge> getRealizedEdges() {
return regionAnalysis.getRealizedEdges();
}
public @NonNull List<@NonNull Node> getRealizedExecutionNodes() {
List<@NonNull Node> realizedExecutionNodes = new ArrayList<>();
for (@NonNull Node node : getRealizedMiddleNodes()) {
if (QVTrNameGenerator.TRACECLASS_PROPERTY_NAME.equals(node.getName())) {
realizedExecutionNodes.add(node);
}
// else if (QVTrelationNameGenerator.DISPATCHCLASS_SELF_NAME.equals(node.getName())) {
// realizedExecutionNodes.add(node);
// }
}
return realizedExecutionNodes;
}
public @NonNull Iterable<@NonNull Node> getRealizedMiddleNodes() {
return regionAnalysis.getRealizedMiddleNodes();
}
public @NonNull Iterable<@NonNull NavigableEdge> getRealizedOutputEdges() {
return regionAnalysis.getRealizedOutputEdges();
}
public @NonNull Iterable<@NonNull Node> getRealizedOutputNodes() {
return regionAnalysis.getRealizedOutputNodes();
}
public @NonNull List<@NonNull Node> getRealizedWhereNodes() {
List<@NonNull Node> realizedWhereNodes = new ArrayList<>();
for (@NonNull Node node : getRealizedMiddleNodes()) {
if (node.getName().startsWith("where_")) {
realizedWhereNodes.add(node);
}
}
return realizedWhereNodes;
}
public @Nullable AbstractPartialPartition getRealizingPartition(@NonNull Edge edge) {
return alreadyRealizedEdges.get(edge);
}
public @NonNull MappingRegion getRegion() {
return region;
}
public @NonNull RegionAnalysis getRegionAnalysis() {
return regionAnalysis;
}
public @NonNull RegionsAnalysis<@NonNull Partition> getRegionsPartitionAnalysis() {
return regionsPartitionAnalysis;
}
protected @NonNull ScheduleManager getScheduleManager() {
return scheduleManager;
}
private @NonNull Iterable<@NonNull Node> getSpeculationReachabilityRootNodes() {
List<@NonNull Node> rootNodes = new ArrayList<>();
for (@NonNull Node headNode : QVTscheduleUtil.getHeadNodes(region)) {
if (!headNode.isDependency()) {
rootNodes.add(headNode);
}
}
for (@NonNull Node constantInputNode : getConstantInputNodes()) {
rootNodes.add(constantInputNode);
}
return rootNodes;
}
public @NonNull Iterable<@NonNull SuccessEdge> getSuccessEdges() {
return regionAnalysis.getSuccessEdges();
}
public @Nullable Iterable<@NonNull TraceClassAnalysis<@NonNull RegionAnalysis>> getSuperProducedTraceClassAnalyses() {
return regionAnalysis.getSuperProducedTraceClassAnalyses();
}
public @NonNull TraceClassAnalysis<@NonNull RegionAnalysis> getTraceClassAnalysis(@NonNull Node traceNode) {
ClassDatum traceClassDatum = QVTscheduleUtil.getClassDatum(traceNode);
return transformationAnalysis.getTraceClassAnalysis(traceClassDatum);
}
public @Nullable Edge getTraceEdge(@NonNull Node node) {
return regionAnalysis.getTraceEdge(node);
}
public @NonNull Node getTraceNode() {
List<@NonNull Node> traceNodes = getTraceNodes();
assert traceNodes.size() == 1;
return ClassUtil.nonNullState(traceNodes.get(0));
}
public @NonNull List<@NonNull Node> getTraceNodes() {
return regionAnalysis.getTraceNodes();
}
public boolean hasConstantEdge(@NonNull Edge edge) {
return alreadyConstantEdges.contains(edge);
}
public boolean hasLoadedEdge(@NonNull Edge edge) {
return alreadyLoadedEdges.contains(edge);
}
public boolean hasPredicatedEdge(@NonNull Edge edge) {
return alreadyPredicatedEdges.contains(edge);
}
public boolean hasPredicatedNode(@NonNull Node node) {
return alreadyPredicatedNodes.contains(node);
}
public boolean hasRealizedEdge(@NonNull Edge edge) {
return alreadyRealizedEdges.containsKey(edge);
}
public boolean hasRealizedNode(@NonNull Node node) {
return alreadyRealizedNodes.contains(node);
}
public @Nullable List<@NonNull Region> getCorollaryOf(@NonNull NavigableEdge edge) {
return transformationAnalysis.getCorollaryOf(edge);
}
public boolean isCyclic(@NonNull Node traceNode) {
ClassDatum traceClassDatum = QVTscheduleUtil.getClassDatum(traceNode);
return transformationAnalysis.isCyclic(traceClassDatum);
}
private boolean isDead(@NonNull Node node, @Nullable Set<@NonNull Node> knownDeadNodes) {
if (node.isHead()) {
return false;
}
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if ((edge.isCast() || edge.isNavigation())) {
if ((knownDeadNodes == null) || !knownDeadNodes.contains(edge.getEdgeSource())) {
return false;
}
}
else if (edge.isPredicate()) {
if ((knownDeadNodes == null) || !knownDeadNodes.contains(edge.getEdgeSource())) {
return false;
}
}
// else if (edge.isExpression() && edge.isPredicated()) {
// return false;
// }
}
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(node)) {
if (edge.isCast() || edge.isNavigation() || edge.isExpression()) {
if ((knownDeadNodes == null) || !knownDeadNodes.contains(edge.getEdgeTarget())) {
return false;
}
}
}
return true;
}
/* private boolean isDead(@NonNull Edge edge) {
if (!edge.isExpression()) {
return false;
}
Node node = edge.getTarget();
for (@NonNull Edge incomingEdge : node.getIncomingEdges()) {
if ((incomingEdge != edge) && incomingEdge.isMatched()) {
return false;
}
}
for (@NonNull Edge outgoingEdge : node.getOutgoingEdges()) {
if (!isDead(outgoingEdge)) {
return false;
}
}
return true;
} */
public @NonNull Iterable<@NonNull Partition> partition() {
if ((region instanceof DispatchRegion) || (region instanceof VerdictRegion)) {
return Collections.singletonList(createNonPartition());
}
String name = region.getName();
if ("associationToForeignKey".equals(name)) {
getClass();
}
boolean isCyclic = transformationAnalysis.isCyclic(regionAnalysis);
// boolean isInfallible = false;
// if (cycleAnalysis != null) {
// isInfallible = cycleAnalysis.isInfallible();
// }
boolean hasPredication = false;
boolean needsActivator = false;
boolean useActivators = scheduleManager.useActivators();
if (useActivators) { // QVTr
List<@NonNull Node> predicatedWhenNodes = getPredicatedWhenNodes();
hasPredication = predicatedWhenNodes.size() > 0;
List<@NonNull Node> realizedExecutionNodes = getRealizedExecutionNodes();
if (realizedExecutionNodes.size() > 0) { // A 'single' realized "trace" node is a boring no-override top activation.
needsActivator = true;
}
else {
needsActivator = false;
}
}
else { // legacy QVTc
Iterable<@NonNull Node> predicatedMiddleNodes = getPredicatedMiddleNodes();
hasPredication = !Iterables.isEmpty(predicatedMiddleNodes);
}
boolean needsSpeculation = isCyclic && hasPredication; //(dispatchedTraceNodes2.isEmpty() ? !predicatedMiddleNodes.isEmpty() : !predicatedMiddleNodes.containsAll(dispatchedTraceNodes2));
//
// Create the partitioned regions
//
List<@NonNull Partition> newPartitions = new ArrayList<>();
if (needsActivator) {
//
// Create an activator to make a QVTr top relation behave as a non-top relation.
//
newPartitions.add(createActivatorPartition());
}
if (!needsSpeculation) {
//
// If speculation is not needed just add the functionality as a single region.
//
if (newPartitions.isEmpty()) { // i.e. a QVTr non top relation - re-use as is
newPartitions.add(createNonPartition());
}
else { // i.e. a QVTr top relation - create a residue to finish off the activator
newPartitions.add(createResidualPartition());
}
}
else { // cycles may need speculation and partitioning into isolated actions
// if (isInfallible) {
// regionAnalysis.getFallibilities()
// }
if (useActivators) {
regionAnalysis.createLocalSuccess();
}
SpeculationPartition speculationPartition = createSpeculationPartition();
SpeculatingPartition speculatingPartition = createSpeculatingPartition();
SpeculatedPartition speculatedPartition = createSpeculatedPartition();
newPartitions.add(speculationPartition);
newPartitions.add(speculatingPartition);
newPartitions.add(speculatedPartition);
if (!useActivators) {
speculatingPartition.addExplicitPredecessor(speculationPartition);
speculatedPartition.addExplicitPredecessor(speculatingPartition);
}
ReachabilityForest assignmentReachabilityForest = new ReachabilityForest(getReachabilityRootNodes(), getAvailableNavigableEdges());
//
// Create an AssignmentRegion for each to-be-realized edge to an output, which may also realize most trace edges too.
//
for (@NonNull NavigableEdge outputEdge : getRealizedOutputEdges()) {
if (!hasRealizedEdge(outputEdge)) {
newPartitions.add(createAssignmentPartition(assignmentReachabilityForest, outputEdge));
}
}
//
// Create an AssignmentRegion for each still to-be-realized edge to an output.
//
for (@NonNull NavigableEdge edge : getRealizedEdges()) {
if (!hasRealizedEdge(edge)) {
newPartitions.add(createAssignmentPartition(assignmentReachabilityForest, edge));
}
}
if (QVTm2QVTs.DEBUG_GRAPHS.isActive()) {
for (@NonNull Partition partition : newPartitions) {
scheduleManager.writeDebugGraphs(partition, null);
}
}
}
if (newPartitions.size() > 1) { // FIXME shouldn't this work anyway when no partitioning was needed?
check(/*isInfallible*/);
}
return newPartitions;
}
@Override
public String toString() {
return region.getName();
}
}