diff options
author | Ed Willink | 2020-01-23 09:05:52 +0000 |
---|---|---|
committer | Ed Willink | 2020-02-25 12:09:26 +0000 |
commit | 193382298bc5da463115e5fefb745c62e993fbc8 (patch) | |
tree | 4feef76a7af75733521266ee386e6cc94501b62e | |
parent | 800ce8e99587345e667f81ec6f044c186f404617 (diff) | |
download | org.eclipse.qvtd-193382298bc5da463115e5fefb745c62e993fbc8.tar.gz org.eclipse.qvtd-193382298bc5da463115e5fefb745c62e993fbc8.tar.xz org.eclipse.qvtd-193382298bc5da463115e5fefb745c62e993fbc8.zip |
[513375] Introduce but do not use ReachabilityPartitioningStrategy
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 |