blob: 39b2c42319951c530c605d4fb9584736fa895852 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2017 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.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.CompleteClass;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.qvtd.compiler.CompilerProblem;
import org.eclipse.qvtd.compiler.internal.qvtm2qvts.MappingRegionAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtm2qvts.RegionHelper;
import org.eclipse.qvtd.compiler.internal.qvtm2qvts.ScheduleManager;
import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.MappingRegion;
import org.eclipse.qvtd.pivot.qvtschedule.MicroMappingRegion;
import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge;
import org.eclipse.qvtd.pivot.qvtschedule.Node;
import org.eclipse.qvtd.pivot.qvtschedule.Role;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import com.google.common.collect.Iterables;
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 corrolaries 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
{
protected final @NonNull ScheduleManager scheduleManager;
/**
* The overall transformation partitioner providing global analysis results.
*/
protected final @NonNull TransformationPartitioner transformationPartitioner;
/**
* The region to be partitioned.
*/
protected final @NonNull MappingRegion region;
/**
* The TraceClassAnalysis instances that are consumed by this MappingPartitioner.
*/
private @Nullable List<@NonNull TraceClassAnalysis> consumedTraceClassAnalyses = null;
/**
* The TraceClassAnalysis instances that are produced by this MappingPartitioner.
*/
private @Nullable List<@NonNull TraceClassAnalysis> producedTraceClassAnalyses = null;
/**
* The TraceClassAnalysis instances and super instances that are produced by this MappingPartitioner.
*/
private @Nullable Set<@NonNull TraceClassAnalysis> superProducedTraceClassAnalyses = null;
/**
* The constant nodes that require no computation from other nodes.
*/
private final @NonNull List<@NonNull Node> leafConstantNodes = new ArrayList<>();
/**
* The map from node to the trace edge by which the node may be located by lookup in a trace node once its trace edge is relaized..
*/
private final @NonNull Map<@NonNull Node, @NonNull Edge> node2traceEdge = new HashMap<>();
/**
* properties that are directly realized from a middle object provided all predicates are satisfied.
*/
private final @NonNull List<@NonNull Edge> predicatedEdges = new ArrayList<>();
private final @NonNull List<@NonNull Node> predicatedMiddleNodes = new ArrayList<>();
private final @NonNull List<@NonNull Node> predicatedOutputNodes = new ArrayList<>();
private final @NonNull List<@NonNull Node> realizedMiddleNodes = new ArrayList<>();
private final @NonNull List<@NonNull Node> realizedOutputNodes = new ArrayList<>();
private final @NonNull Set<@NonNull NavigableEdge> oldPrimaryNavigableEdges = new HashSet<>();
private final @NonNull Set<@NonNull Edge> realizedEdges = new HashSet<>();
private final @NonNull List<@NonNull Edge> realizedOutputEdges = new ArrayList<>();
private final @NonNull List<@NonNull Node> trueNodes = new ArrayList<>();
// private boolean hasLoadedNodes = false;
/**
* The trace nodes and their corresponding status node.
*
* There should normally be exactly one trace node.
*
* There is no trace node for Adolfo's prematurely folded middle optimization and for manual partitionings
* such as attributeColumns in testQVTcCompiler_SimpleUML2RDBMS_CG.
*
* There could be multiple trace nodes after an early merge results. Work in progress.
*/
private final @NonNull Map<@NonNull Node, @Nullable Node> traceNode2statusNode = new HashMap<>();
/**
* The realized edges from the (realized) trace node to a realized (corrolary) ouput node that identify what is
* guaranteed to be created only speculation succeeds.
*/
private final @NonNull List<@NonNull NavigableEdge> corrolaryEdges = new ArrayList<>();
/**
* The realized output nodes guaranteed to be created only speculation succeeds;
* the targets of corrolaryEdges.
*/
private final @NonNull List<@NonNull Node> corrolaryNodes = new ArrayList<>();
/**
* 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 AbstractPartition> alreadyRealizedEdges = new HashMap<>();
/**
* Dynamically growing list of nodes that have been realized by a partition.
*/
private final @NonNull Set<@NonNull Node> alreadyRealizedNodes = new HashSet<>();
/**
* Dynamically growing list of true nodes that have been realized by a partition.
*/
private final @NonNull Set<@NonNull Node> alreadyTrueNodes = new HashSet<>();
private final @NonNull Map<@NonNull Edge, @NonNull List<@NonNull AbstractPartition>> debugEdge2partitions = new HashMap<>();
public MappingPartitioner(@NonNull TransformationPartitioner transformationPartitioner, @NonNull MappingRegion region) {
// super(getTraceNodes(region.getNodes()), getNavigableEdges(region.getNavigationEdges()));
this.scheduleManager = transformationPartitioner.getScheduleManager();
this.transformationPartitioner = transformationPartitioner;
this.region = region;
//
analyzeNodes();
for (@NonNull Node traceNode : analyzeTraceNodes()) {
analyzeStatusNode(traceNode);
analyzeTraceEdges(traceNode);
}
//
analyzeEdges();
}
private void addConsumptionOfMiddleNode(@NonNull Node node) {
predicatedMiddleNodes.add(node);
TraceClassAnalysis consumedTraceAnalysis = transformationPartitioner.addConsumer(node.getCompleteClass(), this);
List<@NonNull TraceClassAnalysis> consumedTraceClassAnalyses2 = consumedTraceClassAnalyses;
if (consumedTraceClassAnalyses2 == null) {
consumedTraceClassAnalyses = consumedTraceClassAnalyses2 = new ArrayList<>();
}
consumedTraceClassAnalyses2.add(consumedTraceAnalysis);
}
private void addCorrolary(@NonNull NavigableEdge edge) {
Node targetNode = edge.getTargetNode();
assert traceNode2statusNode.containsKey(edge.getSourceNode());
assert targetNode.isRealized();
assert !targetNode.isStatus();
assert !corrolaryEdges.contains(edge);
corrolaryEdges.add(edge);
corrolaryNodes.add(targetNode);
transformationPartitioner.addCorrolary(QVTscheduleUtil.getProperty(edge), region);
}
public void addEdge(@NonNull Edge edge, @NonNull Role newEdgeRole, @NonNull AbstractPartition 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.REALIZED) {
alreadyRealizedEdges.put(edge, partition);
}
List<@NonNull AbstractPartition> 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) {
transformationPartitioner.addProblem(problem);
}
private void addProductionOfMiddleNode(@NonNull Node node) {
realizedMiddleNodes.add(node);
TraceClassAnalysis consumedTraceAnalysis = transformationPartitioner.addProducer(node.getCompleteClass(), this);
List<@NonNull TraceClassAnalysis> producedTraceClassAnalyses2 = producedTraceClassAnalyses;
if (producedTraceClassAnalyses2 == null) {
producedTraceClassAnalyses = producedTraceClassAnalyses2 = new ArrayList<>();
}
producedTraceClassAnalyses2.add(consumedTraceAnalysis);
}
public boolean addRealizedNode(@NonNull Node node) {
return alreadyRealizedNodes.add(node);
}
public boolean addTrueNode(@NonNull Node node) {
return alreadyTrueNodes.add(node);
}
private void analyzeEdges() {
for (@NonNull Edge edge : QVTscheduleUtil.getOwnedEdges(region)) {
if (!edge.isSecondary()) {
if (edge.isPredicated()) {
predicatedEdges.add(edge);
}
if (edge.isNavigation()) {
if (edge.isRealized()) {
realizedEdges.add(edge);
Node sourceNode = edge.getEdgeSource();
Node targetNode = edge.getEdgeTarget();
if (traceNode2statusNode.containsKey(sourceNode)) {
if (targetNode.isRealized() && !targetNode.isStatus()) {
addCorrolary((NavigableEdge) edge);
}
}
else if ((sourceNode.isPredicated() || sourceNode.isRealized())) {
if (!traceNode2statusNode.containsKey(targetNode) && (targetNode.isPredicated() || targetNode.isRealized())) {
realizedOutputEdges.add(edge);
}
}
if (targetNode.isLoaded() && scheduleManager.isMiddle(sourceNode)) {
// navigableEdges.add(navigationEdge);
}
}
else if (edge.isMatched() && !edge.isCast()) {
assert !edge.isExpression();
assert !edge.isComputation();
Node targetNode = edge.getEdgeTarget();
if (!targetNode.isExplicitNull()) {
// navigableEdges.add(navigationEdge);
}
}
}
/* else if (QVTscheduleUtil.isRealizedIncludes(edge)) {
realizedEdges.add(edge);
Node sourceNode = edge.getSource();
if ((sourceNode != traceNode) && (sourceNode == Role.PREDICATED || sourceNode == Role.REALIZED)) {
Node targetNode = edge.getTarget();
if ((targetNode != traceNode) && (targetNode == Role.PREDICATED || targetNode == Role.REALIZED)) {
realizedOutputEdges.add(edge);
}
}
if (edge.getTarget().isLoaded() && edge.getSource().getClassDatumAnalysis().getDomainUsage().isMiddle()) {
// navigableEdges.add(navigationEdge);
}
} */
}
}
for (@NonNull NavigableEdge edge : region.getNavigationEdges()) {
if (!edge.isSecondary() && !edge.isRealized()) {
oldPrimaryNavigableEdges.add(edge);
}
}
}
private void analyzeNodes() {
for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) {
if (node.isTrue()) {
trueNodes.add(node);
}
else if (node.isExplicitNull()) {
assert node.isConstant() && hasNoComputationInputs(node);
leafConstantNodes.add(node);
}
else if (node.isPattern()) {
if (node.isConstant()) {
}
else if (node.isLoaded()) {
// hasLoadedNodes = true;
}
else if (scheduleManager.isMiddle(node)) {
if (node.isPredicated()) {
addConsumptionOfMiddleNode(node);
}
else if (node.isRealized()) {
addProductionOfMiddleNode(node);
// for (@NonNull NavigationEdge edge : node.getNavigationEdges()) {
// Node targetNode = edge.getTarget();
// NodeRole targetNodeRole = targetNode.getNodeRole();
// if (!targetNodeRole == Role.PREDICATED && !targetNodeRole == Role.REALIZED) {
// tracedInputNodes.add(targetNode);
// }
// }
}
else if (!node.isExplicitNull()) {
throw new IllegalStateException("middle node must be predicated or realized : " + node);
}
}
else {
if (!node.isOperation()) {
if (node.isPredicated()) {
predicatedOutputNodes.add(node);
}
else if (node.isRealized()) {
realizedOutputNodes.add(node);
}
}
}
}
else if (node.isOperation()) {
if (node.isConstant()) {
if (hasNoComputationInputs(node)) {
leafConstantNodes.add(node);
}
}
else if (node.isRealized()) {
realizedOutputNodes.add(node);
}
}
}
}
private void analyzeStatusNode(@NonNull Node traceNode) {
Node statusNode = null;
Property statusProperty = scheduleManager.basicGetStatusProperty(traceNode);
if (statusProperty != null) {
transformationPartitioner.getSuccessPropertyDatum(statusProperty);
RegionHelper<@NonNull MappingRegion> regionHelper = new RegionHelper<>(scheduleManager, region);
statusNode = regionHelper.createStatusNode();
statusNode.setUtility(Node.Utility.STRONGLY_MATCHED);
@SuppressWarnings("unused")
NavigableEdge statusEdge = regionHelper.createNavigationEdge(traceNode, statusProperty, statusNode, false);
}
traceNode2statusNode.put(traceNode, statusNode);
}
private void analyzeTraceEdges(@NonNull Node traceNode) {
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(traceNode)) {
if ((edge.isNavigation() && edge.isRealized())) {
Node tracedNode = QVTscheduleUtil.getTargetNode(edge);
node2traceEdge.put(tracedNode, edge);
}
}
}
private @NonNull List<@NonNull Node> analyzeTraceNodes() {
if (realizedMiddleNodes.size() == 0) {
return Collections.emptyList();
}
if (realizedMiddleNodes.size() == 1) {
return Collections.singletonList(realizedMiddleNodes.get(0));
}
//
// Compute the Set of all source nodes from which each target can be reached by transitive to-one navigation.
//
Map<@NonNull Node, @NonNull Set<@NonNull Node>> targetFromSourceClosure = new HashMap<>();
for (@NonNull Node targetNode : realizedMiddleNodes) {
targetFromSourceClosure.put(targetNode, Sets.newHashSet(targetNode));
}
for (@NonNull Node sourceNode : realizedMiddleNodes) {
for (@NonNull NavigableEdge navigationEdge : sourceNode.getRealizedNavigationEdges()) {
Node targetNode = navigationEdge.getEdgeTarget();
Set<@NonNull Node> sourceClosure = targetFromSourceClosure.get(targetNode);
if (sourceClosure != null) {
sourceClosure.add(sourceNode);
}
}
}
MappingRegionAnalysis mappingRegionAnalysis = new MappingRegionAnalysis(region);
List<@NonNull Node> headNodes = mappingRegionAnalysis.computeHeadNodes(targetFromSourceClosure, null);
if (headNodes.size() == 0) {
return Collections.emptyList();
}
else {
return Collections.singletonList(headNodes.get(0));
}
}
// public @Nullable Node basicGetStatusNode() {
// return statusNode;
// }
// public @Nullable Node basicGetTraceNode() {
// return traceNode;
// }
private void check() {
for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) {
if ((node.isSpeculated() || node.isRealized()) && !hasRealizedNode(node)) {
transformationPartitioner.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)) {
transformationPartitioner.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) {
transformationPartitioner.addProblem(CompilerUtil.createRegionWarning(region, "Extra " + edge));
}
Set<@NonNull Edge> missingEdgesSet = Sets.newHashSet(allPrimaryEdges);
missingEdgesSet.removeAll(partitionedEdges);
for (@NonNull Edge edge : missingEdgesSet) {
if (transformationPartitioner.getCorrolaryOf(edge) == null) {// && !isDead(edge)) {
transformationPartitioner.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 MicroMappingRegion createAssignmentRegion(@NonNull Edge outputEdge, int i) {
AssignmentPartition assignmentPartition = new AssignmentPartition(this, outputEdge);
MicroMappingRegion microMappingRegion = assignmentPartition.createMicroMappingRegion("«edge" + i + "»", "_p" + i);
scheduleManager.writeDebugGraphs(microMappingRegion, null);
assignmentPartition.check(microMappingRegion);
return microMappingRegion;
}
private @NonNull MicroMappingRegion createRealizedRegion() {
RealizedPartition realizedPartition = new RealizedPartition(this);
MicroMappingRegion microMappingRegion = realizedPartition.createMicroMappingRegion("«realized»", "_r0");
scheduleManager.writeDebugGraphs(microMappingRegion, null);
realizedPartition.check(microMappingRegion);
return microMappingRegion;
}
private @NonNull MicroMappingRegion createSpeculatedRegion() {
SpeculatedPartition speculatedPartition = new SpeculatedPartition(this);
MicroMappingRegion microMappingRegion = speculatedPartition.createMicroMappingRegion("«speculated»", "_p2");
scheduleManager.writeDebugGraphs(microMappingRegion, null);
speculatedPartition.check(microMappingRegion);
return microMappingRegion;
}
private @NonNull MicroMappingRegion createSpeculatingRegion() {
SpeculatingPartition speculatingPartition = new SpeculatingPartition(this);
MicroMappingRegion microMappingRegion = speculatingPartition.createMicroMappingRegion("«speculating»", "_p1");
scheduleManager.writeDebugGraphs(microMappingRegion, null);
speculatingPartition.check(microMappingRegion);
return microMappingRegion;
}
private @NonNull MicroMappingRegion createSpeculationRegion() {
SpeculationPartition speculationPartition = new SpeculationPartition(this);
MicroMappingRegion microMappingRegion = speculationPartition.createMicroMappingRegion("«speculation»", "_p0");
scheduleManager.writeDebugGraphs(microMappingRegion, null);
speculationPartition.check(microMappingRegion);
return microMappingRegion;
}
// public @NonNull Iterable<@NonNull Edge> getAlreadyPredicatedEdges() {
// return alreadyPredicatedEdges;
// }
public @NonNull Iterable<@NonNull Edge> getAlreadyRealizedEdges() {
return alreadyRealizedEdges.keySet();
}
public @Nullable Iterable<@NonNull TraceClassAnalysis> getConsumedTraceClassAnalyses() {
return consumedTraceClassAnalyses;
}
public @NonNull Iterable<@NonNull NavigableEdge> getCorrolaryEdges() {
return corrolaryEdges;
}
public @NonNull Iterable<@NonNull Node> getCorrolaryNodes() {
return corrolaryNodes;
}
public @NonNull Iterable<@NonNull Node> getLeafConstantNodes() {
return leafConstantNodes;
}
public @NonNull Iterable<@NonNull NavigableEdge> getOldPrimaryNavigableEdges() {
return oldPrimaryNavigableEdges;
}
public @NonNull Iterable<@NonNull Edge> getPredicatedEdges() {
return predicatedEdges;
}
public @NonNull Iterable<@NonNull Node> getPredicatedMiddleNodes() {
return predicatedMiddleNodes;
}
public @NonNull Iterable<@NonNull Node> getPredicatedOutputNodes() {
return predicatedOutputNodes;
}
public @Nullable Iterable<@NonNull TraceClassAnalysis> getProducedTraceClassAnalyses() {
return producedTraceClassAnalyses;
}
public @NonNull Iterable<@NonNull Edge> getRealizedEdges() {
return realizedEdges;
}
// public @NonNull Iterable<@NonNull Node> getRealizedMiddleNodes() {
// return realizedMiddleNodes;
// }
public @NonNull Iterable<@NonNull Node> getRealizedOutputNodes() {
return realizedOutputNodes;
}
public @Nullable AbstractPartition getRealizingPartition(@NonNull Edge edge) {
return alreadyRealizedEdges.get(edge);
}
public @NonNull MappingRegion getRegion() {
return region;
}
protected @NonNull ScheduleManager getScheduleManager() {
return scheduleManager;
}
public @Nullable Node getStatusNode(@NonNull Node traceNode) {
return traceNode2statusNode.get(traceNode);
}
public @Nullable Iterable<@NonNull TraceClassAnalysis> getSuperProducedTraceClassAnalyses() {
List<@NonNull TraceClassAnalysis> producedTraceClassAnalyses2 = producedTraceClassAnalyses;
if (producedTraceClassAnalyses2 != null) {
Set<@NonNull TraceClassAnalysis> superProducedTraceClassAnalyses2 = superProducedTraceClassAnalyses;
if (superProducedTraceClassAnalyses2 == null) {
superProducedTraceClassAnalyses = superProducedTraceClassAnalyses2 = new HashSet<>();
}
for (@NonNull TraceClassAnalysis producedTraceClassAnalysis : producedTraceClassAnalyses2) {
Iterables.addAll(superProducedTraceClassAnalyses2, producedTraceClassAnalysis.getSuperTraceClassAnalyses());
}
}
return superProducedTraceClassAnalyses;
}
public @NonNull TraceClassAnalysis getTraceClassAnalysis(@NonNull Node traceNode) {
CompleteClass traceClass = traceNode.getCompleteClass();
return transformationPartitioner.getTraceClassAnalysis(traceClass);
}
public @Nullable Edge getTraceEdge(@NonNull Node node) {
return node2traceEdge.get(node);
}
public @NonNull Iterable<@NonNull Node> getTraceNodes() {
return traceNode2statusNode.keySet();
}
public @NonNull TransformationPartitioner getTransformationPartitioner() {
return transformationPartitioner;
}
public @NonNull Iterable<@NonNull Node> getTrueNodes() {
return trueNodes;
}
private boolean hasNoComputationInputs(@NonNull Node node) {
for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(node)) {
if (edge.isComputation()) {
return false;
}
}
return true;
}
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 boolean hasTrueNode(@NonNull Node node) {
return alreadyTrueNodes.contains(node);
}
public @Nullable List<@NonNull MappingRegion> getCorrolaryOf(@NonNull Edge edge) {
return transformationPartitioner.getCorrolaryOf(edge);
}
public boolean isCyclic(@NonNull Node node) {
CompleteClass traceClass = node.getCompleteClass();
return transformationPartitioner.isCyclic(traceClass);
}
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.isNavigation()) {
if ((knownDeadNodes == null) || !knownDeadNodes.contains(edge.getEdgeSource())) {
return false;
}
}
}
for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(node)) {
if (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 MappingRegion> partition() {
// System.out.println(" partition " + region);
// Node traceNode2 = traceNode;
// assert traceNode2 != null; // Regular mapping
// if (!hasLoadedNodes) { // No inputs
// Collections.singletonList(region);
// } else
if (transformationPartitioner.getCycleAnalysis(this) == null) { // Cycle analysis failed
return Collections.singletonList(region);
}
// else if (region.getName().startsWith(QVTrNameGenerator.OVERRIDDEN_PREFIX)) { // FIXME better test
// return Collections.singletonList(region);
// }
else {
List<@NonNull MappingRegion> regions = new ArrayList<>();
if (predicatedMiddleNodes.isEmpty()) {
regions.add(createRealizedRegion());
}
else {
regions.add(createSpeculationRegion());
regions.add(createSpeculatingRegion());
regions.add(createSpeculatedRegion());
}
//
// Create an AssignmentRegion for each to-be-realized edge to an output, which may also realize most trace edges too.
//
for (@NonNull Edge outputEdge : realizedOutputEdges) {
if (!hasRealizedEdge(outputEdge)) {
regions.add(createAssignmentRegion(outputEdge, regions.size()));
}
}
//
// Create an AssignmentRegion for each still to-be-realized edge to an output.
//
for (@NonNull Edge edge : realizedEdges) {
if (!hasRealizedEdge(edge)) {
regions.add(createAssignmentRegion(edge, regions.size()));
}
}
check();
return regions;
}
}
@Override
public String toString() {
return region.getName();
}
}