Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Willink2020-01-23 09:05:52 +0000
committerEd Willink2020-02-25 12:09:26 +0000
commit193382298bc5da463115e5fefb745c62e993fbc8 (patch)
tree4feef76a7af75733521266ee386e6cc94501b62e
parent800ce8e99587345e667f81ec6f044c186f404617 (diff)
downloadorg.eclipse.qvtd-193382298bc5da463115e5fefb745c62e993fbc8.tar.gz
org.eclipse.qvtd-193382298bc5da463115e5fefb745c62e993fbc8.tar.xz
org.eclipse.qvtd-193382298bc5da463115e5fefb745c62e993fbc8.zip
[513375] Introduce but do not use ReachabilityPartitioningStrategy
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/MappingPartitioner.java10
-rw-r--r--plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/ReachabilityPartitioningStrategy.java866
2 files changed, 875 insertions, 1 deletions
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/MappingPartitioner.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/MappingPartitioner.java
index 205dfef9f..dc6298d7f 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/MappingPartitioner.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/MappingPartitioner.java
@@ -286,8 +286,16 @@ public class MappingPartitioner implements Nameable
private @NonNull PartitioningStrategy createPartitioningStrategy(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis) {
boolean useActivators = scheduleManager.useActivators();
- if (useActivators) { // New QVTr-style spportg without activators
+ if (useActivators) { // New QVTr-style support without activators
return new DefaultPartitioningStrategy(partitionedTransformationAnalysis, this);
+ /* Element2MiddleProperty relation2GlobalSuccessProperty = regionAnalysis.getRuleAnalysis().getRule2TraceGroup().basicGetRelation2GlobalSuccessProperty();
+ if (relation2GlobalSuccessProperty == null) {
+ // return new DefaultPartitioningStrategy(partitionedTransformationAnalysis, this);
+ return new NonPartitioningStrategy(partitionedTransformationAnalysis, this);
+ }
+ else {
+ return new ReachabilityPartitioningStrategy(partitionedTransformationAnalysis, this);
+ } */
}
else { // Obsolete QVTc-sty;e spportg without activators
return new LegacyPartitioningStrategy(partitionedTransformationAnalysis, this);
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/ReachabilityPartitioningStrategy.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/ReachabilityPartitioningStrategy.java
new file mode 100644
index 000000000..fe6c51ea1
--- /dev/null
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvts2qvts/partitioner/ReachabilityPartitioningStrategy.java
@@ -0,0 +1,866 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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.List;
+import java.util.Map;
+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.UniqueList;
+import org.eclipse.qvtd.compiler.internal.qvtb2qvts.AbstractTransformationAnalysis;
+import org.eclipse.qvtd.compiler.internal.qvtm2qvts.QVTm2QVTs;
+import org.eclipse.qvtd.compiler.internal.qvts2qvts.utilities.ReachabilityForest;
+import org.eclipse.qvtd.compiler.internal.utilities.CompilerUtil;
+import org.eclipse.qvtd.pivot.qvtschedule.BasicPartition;
+import org.eclipse.qvtd.pivot.qvtschedule.BooleanLiteralNode;
+import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
+import org.eclipse.qvtd.pivot.qvtschedule.Edge;
+import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge;
+import org.eclipse.qvtd.pivot.qvtschedule.NavigationEdge;
+import org.eclipse.qvtd.pivot.qvtschedule.Node;
+import org.eclipse.qvtd.pivot.qvtschedule.PropertyDatum;
+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.SuccessNode;
+import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * ReachabilityPartitioningStrategy partitions in accordance with the reachability and dependencies avoiding
+ * any special heuristics for when/where/....
+ */
+public class ReachabilityPartitioningStrategy extends AbstractPartitioningStrategy
+{
+ protected abstract static class AbstractReachabilityPartitionFactory extends AbstractSimplePartitionFactory
+ {
+ /**
+ * The strategy that supervises the partition and accumulates the novelties.
+ */
+ protected final @NonNull ReachabilityPartitioningStrategy strategy;
+
+ /**
+ * The name for the partition.
+ */
+ protected final @NonNull String name;
+
+ /**
+ * The depth and reachability of nodes in the partition.
+ */
+ protected final @NonNull ReachabilityForest reachabilityForest;
+
+ /**
+ * The nodes from the partitioned region that are the pattern match entry points for this partition.
+ */
+ protected final @NonNull Iterable<@NonNull ? extends Node> headNodes;
+
+ /**
+ * The nodes that must appear in the partitioned region and which do not appear in a preceding partition.
+ */
+ protected final @Nullable Iterable<@NonNull ? extends Node> novelNodes;
+
+ /**
+ * The edges that must appear in the partitioned region and which do not appear in a preceding partition.
+ */
+ protected final @Nullable Iterable<@NonNull ? extends Edge> novelEdges;
+
+ /**
+ * The partition factories for the partitions that precede this partition.
+ */
+ private final @NonNull UniqueList<@NonNull AbstractReachabilityPartitionFactory> predecessors = new UniqueList<>();
+
+ /**
+ * The nodes from the partitioned region that are to appear in this partition.
+ */
+ private final @NonNull List<@NonNull Node> reachableNodes = new ArrayList<>();
+
+ /**
+ * The edges from the partitioned region that are to appear in this partition.
+ */
+ private final @NonNull List<@NonNull Edge> reachableEdges = new ArrayList<>();
+
+ protected AbstractReachabilityPartitionFactory(@NonNull ReachabilityPartitioningStrategy strategy, @NonNull ReachabilityForest reachabilityForest,
+ @NonNull Iterable<@NonNull ? extends Node> headNodes, @Nullable Iterable<@NonNull ? extends Node> novelNodes, @Nullable Iterable<@NonNull ? extends Edge> novelEdges) {
+ super(strategy.mappingPartitioner);
+ this.strategy = strategy;
+ strategy.setCurrentPartitionFactory(this);
+ this.name = computeName(ClassUtil.nonNullState(reachabilityForest.getDisambiguator()));
+ this.reachabilityForest = reachabilityForest;
+ this.headNodes = headNodes;
+ this.novelNodes = novelNodes;
+ this.novelEdges = novelEdges;
+ if (novelNodes != null) {
+ for (@NonNull Node node : novelNodes) {
+ addReachableNode(node);
+ }
+ }
+ if (novelEdges != null) {
+ for (@NonNull Edge edge : novelEdges) {
+ addReachableEdge(edge);
+ }
+ }
+ }
+
+ public void addPredecessor(@NonNull AbstractReachabilityPartitionFactory predecessor) {
+ predecessors.add(predecessor);
+ }
+
+ /**
+ * Add edge and its source/targert nodes to the partition.
+ *
+ * Returns true if edge added, false if already present.
+ */
+ private boolean addReachableEdge(@NonNull Edge edge) {
+ if (reachableEdges.contains(edge)) {
+ return false;
+ }
+ addReachableNode(QVTscheduleUtil.getSourceNode(edge));
+ addReachableNode(QVTscheduleUtil.getTargetNode(edge));
+ reachableEdges.add(edge);
+ strategy.addEdge(this, edge);
+ return true;
+ }
+
+ /**
+ * Add node and all transitively preceding nodes to the partition.
+ *
+ * Returns true if node added, false if already present.
+ */
+ private boolean addReachableNode(@NonNull Node node) {
+ if (reachableNodes.contains(node)) {
+ return false;
+ }
+ reachableNodes.add(node);
+ strategy.addNode(this, node);
+ for (@NonNull Node predecessor : reachabilityForest.getPredecessorsClosure(node)) {
+ addReachableNode(predecessor);
+ }
+ return true;
+ }
+
+ public boolean containsNode(@NonNull Node node) {
+ return reachableNodes.contains(node);
+ }
+
+ @Override
+ public @NonNull PartitionAnalysis createPartitionAnalysis(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis) {
+ // Iterable<@NonNull Node> headNodes = QVTscheduleUtil.getHeadNodes(region);
+ BasicPartition partition = createBasicPartition(name, headNodes);
+ for (@NonNull Node node : reachableNodes) {
+ Role role = resolveNodeRole(node);
+ addNode(partition, node, role);
+ }
+ for (@NonNull Edge edge : reachableEdges) {
+ if (!edge.isSecondary()) {
+ Role role = resolveEdgeRole(edge);
+ addEdge(partition, edge, role);
+ }
+ }
+
+
+
+ // Iterable<@NonNull Node> headNodes = QVTscheduleUtil.getHeadNodes(region);
+ // BasicPartition partition = createBasicPartition(name, headNodes);
+ BasicPartitionAnalysis basicPartitionAnalysis = new BasicPartitionAnalysis(partitionedTransformationAnalysis, partition, reachabilityForest, "xyzzy", "xyzzy");
+ // initializePartition(basicPartitionAnalysis);
+ if (QVTm2QVTs.DEBUG_GRAPHS.isActive()) {
+ scheduleManager.writeDebugGraphs(partition, null);
+ }
+ return basicPartitionAnalysis;
+ }
+
+ protected void initPartitionFactory() {
+ //
+ // Grow the nodes to include all not-yet reached reachable nodes.
+ //
+ for (int i = 0; i < reachableNodes.size(); i++) {
+ @NonNull Node sourceNode = reachableNodes.get(i);
+ for (@NonNull Edge edge : QVTscheduleUtil.getOutgoingEdges(sourceNode)) {
+ Node targetNode = QVTscheduleUtil.getTargetNode(edge);
+ AbstractReachabilityPartitionFactory targetPartitionFactory = strategy.basicGetPartitionFactory(targetNode);
+ if (targetPartitionFactory == null) {
+ if (edge.isLoaded()) {
+ addReachableNode(targetNode);
+ }
+ }
+ }
+ }
+ //
+ // Add the edges to nodes to include all not-yet reached reachable nodes.
+ //
+ for (@NonNull Node targetNode : reachableNodes) {
+ for (@NonNull Edge edge : QVTscheduleUtil.getIncomingEdges(targetNode)) {
+ Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
+ AbstractReachabilityPartitionFactory sourcePartitionFactory = strategy.basicGetPartitionFactory(sourceNode);
+ if ((sourcePartitionFactory != null) && reachableNodes.contains(sourceNode)) {
+ addReachableEdge(edge);
+ if (sourcePartitionFactory != this) {
+ addPredecessor(sourcePartitionFactory);
+ }
+ }
+ }
+ }
+ }
+
+ protected @NonNull Role resolveEdgeRole(@NonNull Edge edge) {
+ Role edgeRole = QVTscheduleUtil.getEdgeRole(edge);
+ if ((edgeRole == Role.REALIZED) && (strategy.getPartitionFactory(edge) != this)) {
+ return Role.PREDICATED;
+ }
+ return edgeRole;
+ }
+
+ @Override
+ protected @Nullable Role resolveEdgeRole(@NonNull Role sourceNodeRole, @NonNull Edge edge, @NonNull Role targetNodeRole) {
+ if (mappingPartitioner.hasRealizedEdge(edge)) {
+ return Role.PREDICATED;
+ }
+ Role edgeRole = QVTscheduleUtil.getEdgeRole(edge);
+ // if (edgeRole == Role.REALIZED) {
+ // assert !mappingPartitioner.hasRealizedEdge(edge);
+ // }
+ return edgeRole;
+ }
+
+ protected @NonNull Role resolveNodeRole(@NonNull Node node) {
+ Role nodeRole = QVTscheduleUtil.getNodeRole(node);
+ if ((nodeRole == Role.REALIZED) && (strategy.getPartitionFactory(node) != this)) {
+ return Role.PREDICATED;
+ }
+ return nodeRole;
+ }
+
+ @Override
+ public @NonNull String toString() {
+ return toString(new StringBuilder(), "\n");
+ }
+
+ public @NonNull String toString(@NonNull StringBuilder s, @NonNull String prefix) {
+ s.append(name);
+ s.append(prefix + "\tpredecessors: ");
+ for (@NonNull AbstractReachabilityPartitionFactory predecessor : predecessors) {
+ s.append(" " + predecessor.name);
+ }
+ Iterable<@NonNull ? extends Node> novelNodes2 = novelNodes;
+ if (novelNodes2 != null) {
+ s.append(prefix + "\tnovel nodes");
+ for (@NonNull Node node : novelNodes2) {
+ s.append(prefix + "\t\t" + node);
+ }
+ }
+ Iterable<@NonNull ? extends Edge> novelEdges2 = novelEdges;
+ if (novelEdges2 != null) {
+ s.append(prefix + "\tnovel edges");
+ for (@NonNull Edge edge : novelEdges2) {
+ s.append(prefix + "\t\t" + edge);
+ }
+ }
+ s.append(prefix + "\treachable nodes");
+ for (@NonNull Node node : reachableNodes) {
+ s.append(prefix + "\t\t" + node);
+ }
+ s.append(prefix + "\treachable edges");
+ for (@NonNull Edge edge : reachableEdges) {
+ s.append(prefix + "\t\t" + edge);
+ }
+ return s.toString();
+ }
+ }
+
+ /**
+ * The CtorPartitionFactory creates the trace node and links to the head node(s). If there are multiple
+ * headnodes, inter-head edges are also added so that once the ctor partition is hoisted into the caller,
+ * the caller may improve performance by considering only appropriately inter-related heads.
+ */
+ protected static class CtorPartitionFactory extends AbstractReachabilityPartitionFactory
+ {
+ protected CtorPartitionFactory(@NonNull ReachabilityPartitioningStrategy strategy, @NonNull ReachabilityForest reachabilityForest,
+ @NonNull Iterable<@NonNull ? extends Node> headNodes, @NonNull Iterable<@NonNull ? extends Node> novelNodes, @NonNull Iterable<@NonNull ? extends Edge> novelEdges) {
+ super(strategy, reachabilityForest, headNodes, novelNodes, novelEdges);
+ // initPartitionFactory(); // no magic growth
+ }
+
+ @Override
+ protected void initPartitionFactory() {
+ throw new UnsupportedOperationException(); // All done in constructor, no magic growth.
+ }
+
+ @Override
+ protected @NonNull Role resolveNodeRole(@NonNull Node node) {
+ Role nodeRole = node.getNodeRole();
+ if (nodeRole == Role.REALIZED) {
+ return Role.SPECULATION;
+ }
+ return super.resolveNodeRole(node);
+ }
+ }
+
+ /**
+ * The InitPartitionFactory checks all predicates that can be established independent of the success of concurrent partitions.
+ * The local success is assigned on completion.
+ */
+ protected static class InitPartitionFactory extends AbstractReachabilityPartitionFactory
+ {
+ protected InitPartitionFactory(@NonNull ReachabilityPartitioningStrategy strategy, @NonNull ReachabilityForest reachabilityForest,
+ @NonNull Iterable<@NonNull ? extends Node> headNodes, @NonNull Iterable<@NonNull ? extends Node> novelNodes) {
+ super(strategy, reachabilityForest, headNodes, novelNodes, null);
+ initPartitionFactory();
+ }
+
+ @Override
+ protected @NonNull Role resolveNodeRole(@NonNull Node node) {
+ if (node.isTrace()) {
+ return Role.SPECULATED;
+ }
+ return super.resolveNodeRole(node);
+ }
+ }
+
+ /**
+ * The LoopPartitionFactory defines the decision stage in the execution.
+ *
+ * The preceding CtorPartitionFactory creates the trace. Then the preceding InitPartitionFactory checks all
+ * predicates that are dependent solely on earlier executing partitions.
+ *
+ * The LoopPartitionFactory checks the remaining non-corrolary predicates that have cyclic dependencies on
+ * concurrently executing partitions. Once cycle execution has been validated, success is assigned true, and
+ * all remaining realized nodes are created.
+ *
+ * Thereafter the RestPartitionFactory instances realize edges that are predicated solely on corrolary
+ * predicates.
+ */
+ protected static class LoopPartitionFactory extends AbstractReachabilityPartitionFactory
+ {
+ protected LoopPartitionFactory(@NonNull ReachabilityPartitioningStrategy strategy, @NonNull ReachabilityForest reachabilityForest,
+ @NonNull Iterable<@NonNull ? extends Node> headNodes, @NonNull Iterable<@NonNull ? extends Node> novelNodes, @NonNull Iterable<@NonNull ? extends Edge> novelEdges) {
+ super(strategy, reachabilityForest, headNodes, novelNodes, novelEdges);
+ initPartitionFactory();
+ }
+
+ @Override
+ protected @NonNull Role resolveEdgeRole(@NonNull Edge edge) {
+ CyclicRegionAnalysis cyclicRegionAnalysis = strategy.basicGetCyclicRegionAnalysis();
+ if (cyclicRegionAnalysis != null) {
+ if ((edge.getEdgeRole() == Role.PREDICATED) && (edge instanceof SuccessEdge)) {
+ assert !edge.isSecondary();
+ SuccessEdge navigationEdge = (SuccessEdge) edge;
+ PropertyDatum propertyDatum = strategy.scheduleManager.getPropertyDatum(navigationEdge);
+ if (cyclicRegionAnalysis.isCyclic(propertyDatum)) {
+ Node targetNode = QVTscheduleUtil.getTargetNode(navigationEdge);
+ if ((targetNode instanceof BooleanLiteralNode) && ((BooleanLiteralNode)targetNode).isBooleanValue()) {
+ return Role.SPECULATED;
+ }
+ }
+ }
+ }
+ return super.resolveEdgeRole(edge);
+ }
+
+ @Override
+ protected @NonNull Role resolveNodeRole(@NonNull Node node) {
+ if (node.isTrace()) {
+ return Role.SPECULATED;
+ }
+ if (node == strategy.localSuccessNode) {
+ return Role.CONSTANT_SUCCESS_TRUE;
+ }
+ return super.resolveNodeRole(node);
+ }
+ }
+
+ protected static class RestPartitionFactory extends AbstractReachabilityPartitionFactory
+ {
+ protected RestPartitionFactory(@NonNull ReachabilityPartitioningStrategy strategy, @NonNull ReachabilityForest reachabilityForest,
+ @NonNull Iterable<@NonNull ? extends Node> headNodes, @NonNull Iterable<@NonNull ? extends Node> novelNodes, @NonNull Iterable<@NonNull ? extends Edge> novelEdges) {
+ super(strategy, reachabilityForest, headNodes, novelNodes, novelEdges);
+ initPartitionFactory();
+ }
+
+ @Override
+ protected @NonNull Role resolveNodeRole(@NonNull Node node) {
+ if (node instanceof SuccessNode) {
+ return Role.CONSTANT_SUCCESS_TRUE;
+ }
+ return super.resolveNodeRole(node);
+ }
+ }
+
+ /**
+ * The region to be partitioned,
+ */
+ protected final @NonNull Region region;
+
+ /**
+ * The nodes in the synthesized region. Excludes the additional localSuccess node.
+ */
+ private final @NonNull Iterable<@NonNull Node> originalNodes;
+
+ /**
+ * The edges in the synthesized region. Excludes the additional localSuccess edge.
+ */
+ private final @NonNull Iterable<@NonNull Edge> originalEdges;
+
+ // FIXME Merge state into mappingPartitioner once other factories obsolete.
+ /**
+ * The ordered list of all ProtoPartition to support the Region.
+ */
+ private final @NonNull List<@NonNull AbstractReachabilityPartitionFactory> partitionFactories = new ArrayList<>();
+
+ /**
+ * Mapping from each Region node to the first ProtoPartition in which the node is used.
+ */
+ private final @NonNull Map<@NonNull Node, @NonNull AbstractReachabilityPartitionFactory> node2partitionFactory = new HashMap<>();
+
+ /**
+ * Mapping from each Region edge to the first ProtoPartition in which the edge is used.
+ */
+ private final @NonNull Map<@NonNull Edge, @NonNull AbstractReachabilityPartitionFactory> edge2partitionFactory = new HashMap<>();
+
+ /**
+ * The node that represemts the transformation instance.
+ */
+ // private final @Nullable Node thisNode;
+
+ /**
+ * The node that traces the region execution.
+ *
+ * Currently always a node. If multiple nodes are ever needed for a merge we will probably need
+ * to actually merge the trace and so again have just one trace node.
+ */
+ // private final @NonNull Node traceNode;
+
+ private final @NonNull Iterable<@NonNull Node> thisAndTraceNodes;
+
+ /**
+ * The loop/global success node that is realized in the region.
+ */
+ private final @NonNull SuccessNode globalSuccessNode;
+
+ /**
+ * The init/local success edge that is realized in the region.
+ */
+ private @Nullable SuccessEdge localSuccessEdge = null;
+ private @Nullable SuccessNode localSuccessNode = null;
+
+ // private @Nullable List<@NonNull Node> constantSourceNodes;
+
+ private @NonNull List<@NonNull Node> thisAndTraceAndConstantSourceNodes = new ArrayList<>();
+
+ private @Nullable AbstractReachabilityPartitionFactory currentPartitionFactory = null;
+
+ public ReachabilityPartitioningStrategy(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis, @NonNull MappingPartitioner mappingPartitioner) {
+ super(partitionedTransformationAnalysis, mappingPartitioner);
+ assert scheduleManager.useActivators();
+ assert false;
+ this.region = regionAnalysis.getRegion();
+ this.originalNodes = Lists.newArrayList(QVTscheduleUtil.getOwnedNodes(region));
+ this.originalEdges = Lists.newArrayList(QVTscheduleUtil.getOwnedEdges(region));
+ SuccessNode globalSuccessNode = null;
+ Node thisNode = null;
+ Node traceNode = null;
+ for (@NonNull Node node : originalNodes) {
+ if (node.isThis()) {
+ assert thisNode == null : "Only one this node permitted in " + region.getName();
+ thisNode = node;
+ thisAndTraceAndConstantSourceNodes.add(node);
+ }
+ else if (node.isTrace()) {
+ assert traceNode == null : "Only one trace node permitted in " + region.getName();
+ traceNode = node;
+ thisAndTraceAndConstantSourceNodes.add(node);
+ }
+ else if (node.isSuccess()) {
+ assert globalSuccessNode == null : "Only one success node permitted in " + region.getName();
+ globalSuccessNode = (SuccessNode)node;
+ }
+ else if (node.isConstant() && Iterables.isEmpty(node.getIncomingEdges())) {
+ thisAndTraceAndConstantSourceNodes.add(node);
+ }
+ }
+ assert globalSuccessNode != null : "No global success node in " + region.getName();
+ this.globalSuccessNode = globalSuccessNode;
+ // this.thisNode = thisNode;
+ assert traceNode != null : "No trace node in " + region.getName();
+ // this.traceNode = traceNode;
+ this.thisAndTraceNodes = thisNode != null ? Lists.newArrayList(thisNode, traceNode) : Collections.singletonList(traceNode);
+ }
+
+ private void addEdge(@NonNull AbstractReachabilityPartitionFactory partitionFactory, @NonNull Edge edge) {
+ if (!edge2partitionFactory.containsKey(edge)) {
+ edge2partitionFactory.put(edge, partitionFactory);
+ }
+ }
+
+ private void addNode(@NonNull AbstractReachabilityPartitionFactory partitionFactory, @NonNull Node node) {
+ if (!node2partitionFactory.containsKey(node)) {
+ node2partitionFactory.put(node, partitionFactory);
+ }
+ }
+
+ private @Nullable CyclicRegionAnalysis basicGetCyclicRegionAnalysis() {
+ return transformationAnalysis.basicGetCyclicRegionAnalysis(regionAnalysis);
+ }
+
+ protected @Nullable AbstractReachabilityPartitionFactory basicGetPartitionFactory(@NonNull Edge edge) {
+ return edge2partitionFactory.get(edge);
+ }
+
+ protected @Nullable AbstractReachabilityPartitionFactory basicGetPartitionFactory(@NonNull Node node) {
+ return node2partitionFactory.get(node);
+ }
+
+ @Override
+ protected void check() {
+ super.check();
+ for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) {
+ if (node.isPredicated()) {
+ if (node2partitionFactory.get(node) == null) {
+ CompilerUtil.addRegionError(mappingPartitioner.getProblemHandler(), region, "Should have predicated " + node);
+ }
+ }
+ }
+ for (@NonNull Edge edge : QVTscheduleUtil.getOwnedEdges(region)) {
+ if (edge.isPredicated()) {
+ if (edge2partitionFactory.get(edge) == null) {
+ CompilerUtil.addRegionError(mappingPartitioner.getProblemHandler(), region, "Should have predicated " + edge);
+ }
+ }
+ }
+ }
+
+ private void createCtorPartitionFactory() {
+ Iterable<@NonNull Node> headNodes = QVTscheduleUtil.getHeadNodes(region);
+ List<@NonNull Node> novelCtorNodes = new ArrayList<>();
+ List<@NonNull NavigableEdge> novelCtorEdges = new ArrayList<>();
+ //
+ // Gather all head-to-head edges
+ //
+ for (@NonNull Node headNode : headNodes) {
+ novelCtorNodes.add(headNode);
+ for (@NonNull Edge novelEdge : QVTscheduleUtil.getOutgoingEdges(headNode)) {
+ if ((novelEdge instanceof NavigableEdge) && novelEdge.isLoaded() && Iterables.contains(headNodes, QVTscheduleUtil.getTargetNode(novelEdge))) {
+ novelCtorEdges.add((NavigableEdge)novelEdge);
+ }
+ }
+ }
+ //
+ // Gather all head-to-trace edges
+ //
+ for (@NonNull Node traceNode : thisAndTraceNodes) {
+ if (!novelCtorNodes.contains(traceNode)) { // dispatched head is a trace node
+ novelCtorNodes.add(traceNode);
+ for (@NonNull Edge novelEdge : QVTscheduleUtil.getOutgoingEdges(traceNode)) {
+ if ((novelEdge instanceof NavigableEdge) && Iterables.contains(headNodes, QVTscheduleUtil.getTargetNode(novelEdge))) {
+ novelCtorEdges.add((NavigableEdge)novelEdge);
+ }
+ }
+ }
+ }
+ if (!novelCtorEdges.isEmpty() || (novelCtorNodes.size() > 1)) { // Skip trivial trace only partition
+ ReachabilityForest ctorReachabilityForest = new ReachabilityForest("ctor", headNodes, novelCtorEdges);
+ new CtorPartitionFactory(this, ctorReachabilityForest, headNodes, novelCtorNodes, novelCtorEdges);
+ }
+ }
+
+ private void createInitPartitionFactory() {
+ //
+ // Create the InitPartitionFactory for acyclic elements that precede the cycle.
+ //
+ // FIXME an ordering of the acyclic unpartitioned regions could allow many predicate steps to
+ // be merged from the outset.
+ //
+
+ CyclicRegionAnalysis cyclicRegionAnalysis = basicGetCyclicRegionAnalysis();
+ //
+ // Gather the acyclic edges and remember if there is a cyclic edge.
+ //
+ boolean hasCyclicEdge = false;
+ List<@NonNull NavigableEdge> reachingInitEdges = new ArrayList<>();
+ // Set<@NonNull Node> oldNodes1 = new HashSet<>();
+ for (@NonNull Edge edge : originalEdges) {
+ boolean isReaching = false;
+ if (edge.isNavigable()) {
+ NavigationEdge navigationEdge = (NavigationEdge) edge;
+ if (basicGetPartitionFactory(edge) != null) {
+ isReaching = true;
+ }
+ if (edge.isOld() && !edge.isSecondary()) {
+ if (cyclicRegionAnalysis != null) {
+ PropertyDatum propertyDatum = scheduleManager.getPropertyDatum(navigationEdge);
+ if (cyclicRegionAnalysis.isCyclic(propertyDatum)) {
+ hasCyclicEdge = true;
+ }
+ else {
+ isReaching = true;
+ }
+ }
+ else {
+ isReaching = true;
+ }
+ }
+ if (isReaching) {
+ reachingInitEdges.add(navigationEdge);
+ }
+ }
+ // else {//if (edge.isOld() && !edge.isSecondary()) {
+ // isReaching = true;
+ // }
+ // if (isReaching) {
+ // oldNodes1.add(QVTscheduleUtil.getSourceNode(edge));
+ // oldNodes1.add(QVTscheduleUtil.getTargetNode(edge));
+ // }
+ }
+ /* Set<@NonNull Node> oldNodes1 = new HashSet<>();
+ for (@NonNull Node node : allNodes) {
+ if (node.isOld()) {
+ // ClassDatum classDatum = QVTscheduleUtil.getClassDatum(node);
+ // if (!classDatum.isCollectionType()) { // Collection DataTypes are non 1:1 edge ends
+ oldNodes1.add(node);
+ // }
+ }
+ } */
+ // assert hasCyclicEdge1 == hasCyclicEdge2;
+ // Collections.sort(navigableInitEdges1, NameUtil.NAMEABLE_COMPARATOR);
+ // Collections.sort(navigableInitEdges2, NameUtil.NAMEABLE_COMPARATOR);
+ // assert navigableInitEdges1.equals(navigableInitEdges2);
+
+ // strategy.regionAnalysis.createLocalSuccess();
+ ReachabilityForest initReachabilityForest = new ReachabilityForest("init", thisAndTraceAndConstantSourceNodes, reachingInitEdges);
+ // Set<@NonNull Node> oldNodes2 = Sets.newHashSet(initReachabilityForest.getMostReachableFirstNodes());
+ // assert oldNodes1.equals(oldNodes2);
+ List<@NonNull Node> novelInitNodes1 = null;
+ for (@NonNull Node node : initReachabilityForest.getMostReachableFirstNodes()) {
+ if ((basicGetPartitionFactory(node) == null) && !Iterables.contains(thisAndTraceNodes, node)) {
+ if (novelInitNodes1 == null) {
+ novelInitNodes1 = new ArrayList<>();
+ }
+ novelInitNodes1.add(node);
+ }
+ }
+ /* List<@NonNull Node> novelInitNodes2 = null;
+ for (@NonNull Node node : allNodes) { //initReachabilityForest.getMostReachableFirstNodes()) {
+ AbstractReachabilityPartitionFactory partitionFactory = basicGetPartitionFactory(node);
+ if (partitionFactory == null) {
+ if (novelInitNodes2 == null) {
+ novelInitNodes2 = new ArrayList<>();
+ }
+ novelInitNodes2.add(node);
+ }
+ } */
+ if (novelInitNodes1 != null) {
+ // assert novelInitNodes1.equals(novelInitNodes2); -- not even close
+ if (!hasCyclicEdge) { // Acyclic - can do realizes now
+ for (@NonNull Node node : originalNodes) {
+ if (node.isRealized() && !novelInitNodes1.contains(node) && (basicGetPartitionFactory(node) == null)) {
+ ClassDatum classDatum = QVTscheduleUtil.getClassDatum(node);
+ if (!classDatum.isCollectionType()) { // Collection DataTypes are non 1:1 edge ends
+ novelInitNodes1.add(node);
+ }
+ }
+ }
+ }
+ if (!novelInitNodes1.contains(globalSuccessNode)) {
+ novelInitNodes1.add(getLocalSuccessNode());
+ }
+ new InitPartitionFactory(this, initReachabilityForest, thisAndTraceNodes, novelInitNodes1);
+ }
+ }
+
+ private void createLoopPartitionFactory() {
+ //
+ // Determine the reaching edges for the LoopPartitionFactory.
+ //
+ List<@NonNull NavigableEdge> reachingLoopEdges = new ArrayList<>();
+ for (@NonNull Edge edge : originalEdges) {
+ if (edge.isNavigable()) {
+ boolean isReaching = false;
+ NavigationEdge navigationEdge = (NavigationEdge)edge;
+ if (basicGetPartitionFactory(edge) != null) {
+ isReaching = true; // Gather all already predicated/realized edges.
+ }
+ else if (edge.isOld() && !edge.isSecondary() && !transformationAnalysis.isCorollary(navigationEdge)) {
+ isReaching = true; // Gather all predicated edges that cannot be deferred to the rest partition as corrolaries.
+ }
+ if (isReaching) {
+ reachingLoopEdges.add(navigationEdge);
+ }
+ }
+ }
+ if (localSuccessEdge != null) {
+ reachingLoopEdges.add(localSuccessEdge);
+ }
+ //
+ // Determine the novel nodes for the LoopPartitionFactory.
+ //
+ ReachabilityForest loopReachabilityForest = new ReachabilityForest("loop", thisAndTraceAndConstantSourceNodes, reachingLoopEdges);
+ List<@NonNull Node> novelLoopNodes = null;
+ for (@NonNull Node node : loopReachabilityForest.getMostReachableFirstNodes()) {
+ if (basicGetPartitionFactory(node) == null) {
+ if (novelLoopNodes == null) {
+ novelLoopNodes = new ArrayList<>();
+ }
+ novelLoopNodes.add(node);
+ }
+ }
+ if (novelLoopNodes != null) {
+ if (localSuccessNode != null) {
+ novelLoopNodes.add(localSuccessNode);
+ }
+ for (@NonNull Node node : originalNodes) {
+ if (node.isRealized() && !novelLoopNodes.contains(node) && (basicGetPartitionFactory(node) == null)) {
+ ClassDatum classDatum = QVTscheduleUtil.getClassDatum(node);
+ if (!classDatum.isCollectionType()) { // Collection DataTypes are non 1:1 edge ends
+ novelLoopNodes.add(node);
+ }
+ }
+ }
+ // if (!novelLoopNodes.equals(novelLoopNodes2)) {
+ // getClass();
+ // }
+ List<@NonNull Edge> novelLoopEdges = new ArrayList<>();
+ for (@NonNull Edge edge : originalEdges) {
+ if (edge.isRealized() && (basicGetPartitionFactory(edge) == null)) {
+ Node sourceNode = QVTscheduleUtil.getSourceNode(edge);
+ Node targetNode = QVTscheduleUtil.getTargetNode(edge);
+ if (((loopReachabilityForest.basicGetCost(sourceNode) != null) || Iterables.contains(novelLoopNodes, sourceNode))
+ && ((loopReachabilityForest.basicGetCost(targetNode) != null) || Iterables.contains(novelLoopNodes, targetNode))) {
+ novelLoopEdges.add(edge);
+ }
+ }
+ }
+ new LoopPartitionFactory(this, loopReachabilityForest, thisAndTraceNodes, novelLoopNodes, novelLoopEdges);
+ }
+ }
+
+ protected void createNonPartition() {
+ newPartitionAnalyses.add(new NonPartitionFactory(mappingPartitioner).createPartitionAnalysis(partitionedTransformationAnalysis));
+ }
+
+ private void createRestPartitionFactory() {
+ if ("FtoN1_Family2SurnameContainment".equals(region.getName())) {
+ getClass();
+ }
+ //
+ // Create RestPartitionFactory to progress the remaining realized edges.
+ //
+ List<@NonNull Edge> novelRestEdges = null;
+ for (@NonNull Edge edge : originalEdges) {
+ if (edge.isNavigable()) {
+ NavigationEdge navigationEdge = (NavigationEdge) edge;
+ if (edge.isRealized() && (basicGetPartitionFactory(edge) == null)) {
+ if (novelRestEdges == null) {
+ novelRestEdges = new ArrayList<>();
+ }
+ novelRestEdges.add(navigationEdge);
+ }
+ }
+ }
+ if (novelRestEdges != null) {
+ List<@NonNull NavigableEdge> reachingRestEdges = new ArrayList<>();
+ for (@NonNull Edge edge : originalEdges) {
+ if (edge.isNavigable() && !novelRestEdges.contains(edge)) {
+ reachingRestEdges.add((NavigableEdge)edge);
+ }
+ }
+ Iterable<@NonNull Node> novelRestNodes;
+ SuccessEdge localSuccessEdge2 = localSuccessEdge;
+ if ((localSuccessEdge2 != null) && (basicGetPartitionFactory(globalSuccessNode) == null)) {
+ reachingRestEdges.add(localSuccessEdge2);
+ novelRestNodes = Lists.newArrayList(QVTscheduleUtil.getTargetNode(localSuccessEdge2), globalSuccessNode);
+ }
+ else {
+ novelRestNodes = Collections.singletonList(globalSuccessNode);
+ }
+ ReachabilityForest restReachabilityForest = new ReachabilityForest("rest", thisAndTraceAndConstantSourceNodes, reachingRestEdges);
+ new RestPartitionFactory(this, restReachabilityForest, thisAndTraceNodes, novelRestNodes, novelRestEdges);
+ }
+ }
+
+ private @NonNull SuccessNode getLocalSuccessNode() {
+ SuccessNode localSuccessNode2 = localSuccessNode;
+ if (localSuccessNode2 == null) {
+ this.localSuccessEdge = regionAnalysis.createLocalSuccess();
+ this.localSuccessNode = localSuccessNode2 = (SuccessNode) QVTscheduleUtil.getTargetNode(localSuccessEdge);
+ }
+ return localSuccessNode2;
+ }
+
+ private @NonNull AbstractReachabilityPartitionFactory getPartitionFactory(@NonNull Edge edge) {
+ AbstractReachabilityPartitionFactory partitionFactory = edge2partitionFactory.get(edge);
+ return ClassUtil.nonNullState(partitionFactory);
+ }
+
+ private @NonNull AbstractReachabilityPartitionFactory getPartitionFactory(@NonNull Node node) {
+ AbstractReachabilityPartitionFactory partitionFactory = node2partitionFactory.get(node);
+ return ClassUtil.nonNullState(partitionFactory);
+ }
+
+ public @NonNull Region getRegion() {
+ return region;
+ }
+
+ public @NonNull AbstractTransformationAnalysis getTransformationAnalysis() {
+ return transformationAnalysis;
+ }
+
+ @Override
+ public @NonNull Iterable<@NonNull PartitionAnalysis> partition() {
+ String name = regionAnalysis.getName();
+ if ("mapVariable_qvtr".equals(name)) {
+ getClass();
+ }
+ //
+ // Create the PartitionFactories.
+ //
+ createCtorPartitionFactory();
+ createInitPartitionFactory();
+ createLoopPartitionFactory();
+ createRestPartitionFactory();
+ //
+ // Create the partitions.
+ //
+ for (@NonNull AbstractReachabilityPartitionFactory partitionFactory : partitionFactories) {
+ newPartitionAnalyses.add(partitionFactory.createPartitionAnalysis(partitionedTransformationAnalysis));
+ }
+ check();
+ return newPartitionAnalyses;
+ }
+
+ private void setCurrentPartitionFactory(@NonNull AbstractReachabilityPartitionFactory currentPartitionFactory) {
+ if (this.currentPartitionFactory != null) {
+ currentPartitionFactory.addPredecessor(this.currentPartitionFactory);
+ }
+ this.currentPartitionFactory = currentPartitionFactory;
+ partitionFactories.add(currentPartitionFactory);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append(mappingPartitioner.getName());
+ for (@NonNull AbstractReachabilityPartitionFactory partitionFactory : partitionFactories) {
+ s.append("\n\t");
+ partitionFactory.toString(s, "\n\t");
+ }
+ return s.toString();
+ }
+
+ @Override
+ protected boolean useActivators() {
+ return true;
+ }
+} \ No newline at end of file

Back to the top