blob: 6108a3687c487f3f1c377d1996e4f02949235a16 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.CompleteModel;
import org.eclipse.ocl.pivot.Model;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.utilities.NameUtil;
import org.eclipse.ocl.pivot.utilities.PivotConstants;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.qvtd.compiler.CompilerChainException;
import org.eclipse.qvtd.compiler.ProblemHandler;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.ConnectivityChecker;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.LoadingRegionAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.ScheduleManager;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.UtilityAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtb2qvts.AbstractTransformationAnalysis;
import org.eclipse.qvtd.compiler.internal.qvtm2qvts.QVTm2QVTs;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.merger.ConcurrentPartitionMerger;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.merger.SequentialPartitionMerger;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner.PartitionedTransformationAnalysis;
import org.eclipse.qvtd.compiler.internal.qvts2qvts.partitioner.RootPartitionAnalysis;
import org.eclipse.qvtd.pivot.qvtbase.utilities.StandardLibraryHelper;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeHelper;
import org.eclipse.qvtd.pivot.qvtschedule.ClassDatum;
import org.eclipse.qvtd.pivot.qvtschedule.Connection;
import org.eclipse.qvtd.pivot.qvtschedule.LoadingRegion;
import org.eclipse.qvtd.pivot.qvtschedule.MappingRegion;
import org.eclipse.qvtd.pivot.qvtschedule.Partition;
import org.eclipse.qvtd.pivot.qvtschedule.QVTscheduleFactory;
import org.eclipse.qvtd.pivot.qvtschedule.Region;
import org.eclipse.qvtd.pivot.qvtschedule.RootPartition;
import org.eclipse.qvtd.pivot.qvtschedule.RootRegion;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.DomainUsage;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleConstants;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.SymbolNameBuilder;
import com.google.common.collect.Iterables;
/**
* QVTs2QVTi supervises the serialization of a QVTs schedule as a QVTi transformation.
*/
public class QVTs2QVTs extends QVTimperativeHelper
{
protected final @NonNull ScheduleManager scheduleManager;
protected final @NonNull ProblemHandler problemHandler;
protected final @NonNull String rootName;
// private final @NonNull LoadingRegion loadingRegion;
private final @NonNull LoadingRegionAnalysis loadingRegionAnalysis;
protected final @NonNull CompleteModel completeModel;
private final @NonNull Map<@NonNull Region, @NonNull RegionAnalysis> region2regionAnalysis = new HashMap<>();
/**
* The input models that may introduce model elements for transformation.
*/
private final @NonNull Map<@NonNull Model, org.eclipse.qvtd.pivot.qvtschedule.utilities.DomainUsage> inputModels = new HashMap<>();
private final @NonNull StandardLibraryHelper standardLibraryHelper;
// private final @NonNull Map<@NonNull TypedModel, @NonNull Map<@NonNull Property, @NonNull List<@NonNull NavigableEdge>>> typedModel2property2predicatedEdges = new HashMap<>();
// private final @NonNull Map<@NonNull TypedModel, @NonNull Map<@NonNull Property, @NonNull List<@NonNull NavigableEdge>>> typedModel2property2realizedEdges = new HashMap<>();
public QVTs2QVTs(@NonNull ProblemHandler problemHandler, @NonNull ScheduleManager qvtm2qvts, @NonNull String rootName) {
super(qvtm2qvts.getEnvironmentFactory());
this.scheduleManager = qvtm2qvts;
this.standardLibraryHelper = new StandardLibraryHelper(standardLibrary);
this.problemHandler = problemHandler;
this.rootName = rootName;
this.loadingRegionAnalysis = new LoadingRegionAnalysis(scheduleManager, createLoadingRegion()); // FIXME Should treat LoadingRegion uniformly
this.completeModel = environmentFactory.getCompleteModel();
scheduleManager.createConnectionManager(problemHandler, loadingRegionAnalysis);
}
private void computeInputModels() {
for (@NonNull ClassDatum classDatum : scheduleManager.getClassDatums()) {
DomainUsage domainUsage = scheduleManager.getDomainUsage(classDatum);
if (domainUsage.isInput() && !domainUsage.isOutput()) {
Type type = classDatum.getPrimaryClass();
org.eclipse.ocl.pivot.Package asPackage = PivotUtil.getContainingPackage(type);
if ((asPackage != null) && !PivotConstants.ORPHANAGE_URI.equals(asPackage.getURI())) {
Model model = PivotUtil.getContainingModel(type);
if (model != null) {
inputModels.put(model, domainUsage);
}
}
}
// if (!domainUsage.isEnforceable()) {
// Model model = PivotUtil.getContainingModel(classDatumAnalysis.getClassDatum().getType());
// if ((model != null) && !PivotConstants.ORPHANAGE_URI.equals(model.getExternalURI())) {
// inputModels.put(model, domainUsage);
// }
// }
}
if (QVTm2QVTs.DUMP_INPUT_MODEL_TO_DOMAIN_USAGE.isActive()) {
QVTm2QVTs.DUMP_INPUT_MODEL_TO_DOMAIN_USAGE.println(dumpInputModels().reduce("", QVTscheduleUtil.stringJoin("\n\t")));
}
}
/**
* Create a RootContainmentRegion that introduces model elements directly from the input model root, or from
* composition relationships that form part of an extended metamodel that is not known until run-time.
*/
private @NonNull LoadingRegion createRootContainmentRegion(@NonNull RootPartitionAnalysis rootPartitionAnalysis) {
RootRegion rootRootRegion = rootPartitionAnalysis.getRootRegion();
LoadingRegion loadingRegion = loadingRegionAnalysis.getRegion();
// loadingRegion.setOwningRootRegion(rootRootRegion);
assert rootRootRegion.getOwnedLoadingRegion() == loadingRegion;
scheduleManager.writeDebugGraphs(loadingRegion, null);
return loadingRegion;
}
/**
* Create a NodeConnection to the realized node for each attribute.
*
private void createAttributeConnections() {
RootRegion invokingRegion2 = invokingRegion;
assert invokingRegion2 != null;
RootRootRegion rootRootRegion = invokingRegion2.getRootRootRegion();
for (@NonNull NavigationEdge predicatedEdge : getPredicatedNavigationEdges()) {
Node predicatedTarget = predicatedEdge.getTarget();
if (predicatedEdge.isNavigation()
&& !predicatedEdge.isCast()
&& (predicatedTarget.getIncomingConnection() == null)
&& predicatedTarget.isAttributeNode()) { // FIXME isCast does not need to be isNavigation now that it can be isNavigable
Iterable<@NonNull NavigationEdge> realizedEdges = rootRootRegion.getRealizedEdges(predicatedEdge);
if (realizedEdges != null) {
Property predicatedProperty = predicatedEdge.getProperty();
assert !predicatedProperty.isIsImplicit();
ClassDatumAnalysis classDatumAnalysis = predicatedTarget.getClassDatumAnalysis();
List<@NonNull Node> sourceNodes = new ArrayList<>();
for (@NonNull NavigationEdge realizedEdge : realizedEdges) {
sourceNodes.add(realizedEdge.getTarget());
}
NodeConnection nodeConnection = invokingRegion2.getNodeConnection(sourceNodes, classDatumAnalysis);
nodeConnection.addUsedTargetNode(predicatedTarget, false);
if (Scheduler.CONNECTIONS.isActive()) {
Scheduler.CONNECTIONS.println(" Attribute NodeConnection to " + predicatedTarget);
}
}
}
}
} */
protected @NonNull LoadingRegion createLoadingRegion() {
LoadingRegion loadingRegion = QVTscheduleFactory.eINSTANCE.createLoadingRegion();
loadingRegion.setName(rootName + "-" + QVTscheduleConstants.LOAD_MAPPING_NAME);
SymbolNameBuilder s = new SymbolNameBuilder();
s.appendString("__load__"); //QVTscheduleUtil.ROOT_MAPPING_NAME);
loadingRegion.setSymbolName(scheduleManager.getScheduleModel().reserveSymbolName(s, loadingRegion));
return loadingRegion;
}
/**
* Create a NodeConnection to the realized node for each node, unless there is already an EdgeConnection for any edge to/from the node.
*
private void createNodeConnections() {
RootRegion invokingRegion2 = invokingRegion;
assert invokingRegion2 != null;
RootRootRegion rootRootRegion = invokingRegion2.getRootRootRegion();
for (@NonNull Node predicatedNode : getPredicatedNodes()) {
if (!predicatedNode.isLoaded() // WIP and !isOnlyCast
&& !predicatedNode.isConstant()
&& !predicatedNode.isHead()
&& !predicatedNode.isOperation()
&& !predicatedNode.isTrue()
&& (predicatedNode.getIncomingConnection() == null)
&& !predicatedNode.isAttributeNode()
&& !rootRootRegion.isOnlyCastOrRecursed(predicatedNode)
&& !hasEdgeConnection(predicatedNode)) {
ClassDatumAnalysis classDatumAnalysis = predicatedNode.getClassDatumAnalysis();
Iterable<@NonNull Node> sourceNodes = rootRootRegion.getIntroducingOrProducingNodes(classDatumAnalysis);
if (sourceNodes != null) {
NodeConnection predicatedConnection = invokingRegion2.getNodeConnection(sourceNodes, classDatumAnalysis);
predicatedConnection.addUsedTargetNode(predicatedNode, false);
if (Scheduler.CONNECTIONS.isActive()) {
Scheduler.CONNECTIONS.println(" NodeConnection from " + predicatedNode);
}
}
}
}
} */
/**
* Create a NodeConnection to the realized node for each node in the pattern related to a head node.
*
private void createRelatedConnections(@NonNull NodeConnection headConnection) {
@NonNull Iterable<@NonNull Node> headSources = headConnection.getSources();
/**
* Each bindable node is navigable within the guard/predicate from the head and has an equivalent node in every possible caller.
* A bindable node may therefore by passed by value from each of a known set of calling nodes to each called node.
* /
Map<@NonNull NavigationEdge, @NonNull List<@NonNull NavigationEdge>> related2bindableSources = new HashMap<>();
/**
* Each computable node is navigable within the guard/predicate from the head but does not have an equivalent node in every possible caller.
* A computable node cannot always be passed by value. It is therefore recomputed within a known set of calling regions at each called node.
* /
Map<@NonNull Node, @NonNull List<@NonNull Region>> related2computableSources = new HashMap<>();
RootRegion invokingRegion2 = invokingRegion;
assert invokingRegion2 != null;
RootRootRegion rootRootRegion = invokingRegion2.getRootRootRegion();
//
// Categorize the corresponding sources for each related node as uniformly bindable else re-computable.
//
for (@NonNull Node headSource : headSources) {
Region sourceRegion = headSource.getRegion();
assert this != sourceRegion;
for (@NonNull Node headNode : headConnection.getTargets()) {
if ((headNode.getRegion() == this) && headNode.isHead()) {
Map<@NonNull Node, @Nullable Node> calledNode2callingNode = new HashMap<>();
Map<@NonNull NavigationEdge, @Nullable NavigationEdge> calledEdge2callingEdge = new HashMap<>();
computeCompatiblePattern(headNode, headSource, calledNode2callingNode, calledEdge2callingEdge);
for (Map./*@NonNull* /Entry<@NonNull NavigationEdge, @Nullable NavigationEdge> entry : calledEdge2callingEdge.entrySet()) {
@NonNull NavigationEdge calledEdge = entry.getKey();
@NonNull Node calledNode = calledEdge.getTarget();
assert calledNode.isHead() == (calledNode == headNode); // FIXME validating more efficient test
if (!calledNode.isHead()
&& !calledNode.isLoaded()
&& !calledNode.isConstant()
&& !rootRootRegion.isOnlyCastOrRecursed(calledNode)) {
@Nullable NavigationEdge callingEdge = entry.getValue();
if ((callingEdge != null) && !related2computableSources.containsKey(calledNode)) {
List<@NonNull NavigationEdge> bindableSources = related2bindableSources.get(calledEdge);
if (bindableSources == null) {
bindableSources = new ArrayList<>();
related2bindableSources.put(calledEdge, bindableSources);
}
assert !bindableSources.contains(callingEdge);
bindableSources.add(callingEdge);
}
else {
List<@NonNull Region> computableSources = related2computableSources.get(calledNode);
if (computableSources == null) {
computableSources = new ArrayList<>();
related2computableSources.put(calledNode, computableSources);
}
assert !computableSources.contains(sourceRegion);
computableSources.add(sourceRegion);
if (related2bindableSources.containsKey(calledEdge)) {
List<@NonNull NavigationEdge> bindableSources = related2bindableSources.remove(calledEdge);
assert bindableSources != null;
for (@NonNull NavigationEdge bindableSource : bindableSources) {
Region bindableRegion = bindableSource.getRegion();
assert !computableSources.contains(sourceRegion);
computableSources.add(bindableRegion);
}
}
}
}
}
}
}
}
assert Sets.intersection(related2bindableSources.keySet(), related2computableSources.keySet()).isEmpty();
//
// Connect the uniformly bindable calling sources to their called nodes.
//
for (Map./*@NonNull* /Entry<@NonNull NavigationEdge, @NonNull List<@NonNull NavigationEdge>> entry : related2bindableSources.entrySet()) {
@NonNull NavigationEdge calledEdge = entry.getKey();
@NonNull Node calledNode = calledEdge.getTarget();
assert !calledNode.isLoaded() && !calledNode.isConstant();
@NonNull List<@NonNull NavigationEdge> bindableEdges = entry.getValue();
EdgeConnection bindableConnection = invokingRegion2.getEdgeConnection(bindableEdges, calledEdge.getProperty());
bindableConnection.addUsedTargetEdge(calledEdge, false);
if (Scheduler.CONNECTIONS.isActive()) {
Scheduler.CONNECTIONS.println(" Bindable EdgeConnection to " + calledEdge);
}
}
//
// Connect the introducing/producing nodes of the not uniformly bindable calling sources to their called nodes.
//
for (Map./*@NonNull* /Entry<@NonNull Node, @NonNull List<@NonNull Region>> entry : related2computableSources.entrySet()) {
@NonNull Node calledNode = entry.getKey();
assert !calledNode.isLoaded() && !calledNode.isConstant() && !rootRootRegion.isOnlyCastOrRecursed(calledNode);
ClassDatumAnalysis classDatumAnalysis = calledNode.getClassDatumAnalysis();
Iterable<@NonNull Node> introducingOrProducingNodes = rootRootRegion.getIntroducingOrProducingNodes(classDatumAnalysis);
if (introducingOrProducingNodes != null) {
@NonNull List<@NonNull Region> computableRegions = entry.getValue();
List<@NonNull Node> computableSourceNodes = null;
assert calledNode.getRegion() == this; // FIXME just checking simpler test
for (@NonNull Node computableSourceNode : introducingOrProducingNodes) {
Region sourceRegion = computableSourceNode.getRegion();
if ((computableSourceNode.getRegion() != this) && !computableRegions.contains(sourceRegion)) { // FIXME only if a Recursion Edge
if (computableSourceNodes == null) {
computableSourceNodes = new ArrayList<>();
}
computableSourceNodes.add(computableSourceNode);
}
}
if (computableSourceNodes != null) {
NodeConnection computableConnection = invokingRegion2.getNodeConnection(computableSourceNodes, classDatumAnalysis);
computableConnection.addUsedTargetNode(calledNode, false);
if (Scheduler.CONNECTIONS.isActive()) {
Scheduler.CONNECTIONS.println(" Computable NodeConnection to " + calledNode);
}
}
}
}
} */
private Stream<String> dumpInputModels() {
Stream<String> entries = inputModels.keySet().stream().map(
k -> String.valueOf(k) + " : " + String.valueOf(inputModels.get(k)));
return entries.sorted();
}
public @NonNull RegionAnalysis getRegionAnalysis(@NonNull Region region) {
RegionAnalysis regionAnalysis = region2regionAnalysis.get(region);
if (regionAnalysis == null) {
regionAnalysis = scheduleManager.getRegionAnalysis(region);
region2regionAnalysis.put(region, regionAnalysis);
}
return regionAnalysis;
}
/* public @NonNull List<@NonNull Collection<@NonNull Region>> getRegionSchedule(@NonNull CyclicPartitionAnalysis cyclicPartitionAnalysis) {
List<@NonNull Collection<@NonNull Region>> regionSchedule = new ArrayList<>();
for (@NonNull Iterable<@NonNull PartitionAnalysis> concurrentPartitions : cyclicPartitionAnalysis.getPartitionSchedule()) {
List<@NonNull Region> concurrentRegions = new ArrayList<>();
for (@NonNull PartitionAnalysis partitionAnalysis : concurrentPartitions) {
if (partitionAnalysis instanceof CyclicPartitionAnalysis) {
getRegionSchedule(((CyclicPartitionAnalysis)partitionAnalysis));
Iterables.addAll(concurrentRegions, ((CyclicPartitionAnalysis)partitionAnalysis).createMicroMappingRegions());
}
else {
MappingRegion partitionedRegion = partitionAnalysis.createMicroMappingRegion();
concurrentRegions.add(partitionedRegion);
// scheduleManager.wipAddPartition(partition, partitionedRegion);
}
}
regionSchedule.add(concurrentRegions);
}
return regionSchedule;
} */
/* public @NonNull List<@NonNull Collection<@NonNull Region>> getRegionSchedule2(@NonNull RootPartitionAnalysis rootPartitionAnalysis, @NonNull List<@NonNull Iterable<@NonNull Partition>> partitionSchedule) {
RootRegion rootRegion = rootPartitionAnalysis.getRootRegion();
List<@NonNull Collection<@NonNull Region>> regionSchedule = new ArrayList<>();
assert rootRegion != null;
LoadingRegion loadingRegion = rootRegion.getOwnedLoadingRegion();
if (loadingRegion != null) {
regionSchedule.add(Lists.newArrayList(loadingRegion));
}
for (@NonNull Iterable<@NonNull Partition> concurrentPartitions : partitionSchedule) {
List<@NonNull Region> concurrentRegions = new ArrayList<>();
for (@NonNull Partition partition : concurrentPartitions) {
if (partition instanceof CyclicPartition) {
getRegionSchedule(((CyclicPartition)partition));
for (@NonNull PartitionAnalysis partitionAnalysis : ((CyclicPartition)partition).getPartitionAnalyses()) {
MappingRegion mappingRegion = partitionAnalysis.getPartition().getMicroMappingRegion();
concurrentRegions.add(mappingRegion);
}
}
else if (!(partition instanceof LoadingPartition)) {
MappingRegion mappingRegion = partition.getMicroMappingRegion();
concurrentRegions.add(mappingRegion);
}
}
if (concurrentRegions.size() > 0) {
regionSchedule.add(concurrentRegions);
}
}
return regionSchedule;
} */
public @NonNull ScheduleManager getScheduleManager() {
return scheduleManager;
}
public @NonNull StandardLibraryHelper getStandardLibraryHelper() {
return standardLibraryHelper ;
}
/* private void lateMerge(@NonNull RootPartition rootPartition, @NonNull List<@NonNull Collection<@NonNull Region>> parallelSchedule,
@NonNull Map<@NonNull TypedModel, @NonNull Map<@NonNull Property, @NonNull List<@NonNull NavigableEdge>>> typedModel2property2predicatedEdges,
@NonNull Map<@NonNull TypedModel, @NonNull Map<@NonNull Property, @NonNull List<@NonNull NavigableEdge>>> typedModel2property2realizedEdges) {
Map<@NonNull Region, @NonNull Integer> region2depth = new HashMap<>();
int parallelDepth = 0;
for (@NonNull Iterable<@NonNull Region> orderedRegions : parallelSchedule) {
for (@NonNull Region region : orderedRegions) {
region2depth.put(region, parallelDepth);
}
parallelDepth++;
}
Map<@NonNull MappingRegion, @NonNull List<@NonNull MappingRegion>> newRegion2oldRegions = LateConsumerMerger.merge(scheduleManager, rootPartition);
for (Map.Entry<@NonNull MappingRegion, @NonNull List<@NonNull MappingRegion>> entry : newRegion2oldRegions.entrySet()) {
MappingRegion newRegion = entry.getKey();
List<@NonNull MappingRegion> oldRegions = entry.getValue();
assert oldRegions.size() >= 2;
// int orderedRegionIndex = orderedRegions.indexOf(oldRegions.get(0));
Integer orderedRegionIndex = region2depth.get(oldRegions.get(0));
assert orderedRegionIndex != null;
for (@NonNull MappingRegion oldRegion : oldRegions) {
// orderedRegions.remove(oldRegion);
Integer depth = region2depth.get(oldRegion);
assert depth != null;
parallelSchedule.get(depth).remove(oldRegion);
scheduleManager.setRootRegion(oldRegion, null);
}
// orderedRegions.add(orderedRegionIndex, newRegion);
parallelSchedule.get(orderedRegionIndex).add(newRegion);
QVTscheduleConstants.POLLED_PROPERTIES.println("building indexes for " + newRegion + " " + scheduleManager.wipGetPartition(newRegion).getPassRangeText());
// RegionAnalysis regionAnalysis = scheduleManager.getRegionAnalysis(newRegion);
// regionAnalysis.buildNavigationEdgesIndex(typedModel2property2predicatedEdges, typedModel2property2realizedEdges);
}
} */
protected @NonNull PartitionedTransformationAnalysis partition(ScheduleManager scheduleManager, @NonNull RootRegion rootRegion, @NonNull Iterable<? extends @NonNull Region> activeRegions) throws CompilerChainException {
AbstractTransformationAnalysis transformationAnalysis = scheduleManager.getTransformationAnalysis(rootRegion);
PartitionedTransformationAnalysis partitionedTransformationAnalysis = transformationAnalysis.partition(problemHandler, activeRegions);
RootPartitionAnalysis rootPartitionAnalysis = partitionedTransformationAnalysis.getRootPartitionAnalysis();
rootPartitionAnalysis.setRootRegion(rootRegion);
// rootRegion2rootPartition.put(rootRegion, rootPartition);
// Iterable<@NonNull MappingRegion> partitionedRegions = rootPartition.getPartitionedRegions();
// if (!Iterables.isEmpty(partitionedRegions)) {
// for (@NonNull Region region : partitionedRegions) {
// System.out.println("partitionedRegions " + region);
// }
// rootRegion2partitionedRegions.put(rootRegion, partitionedRegions);
// }
// else {
// rootRegion2partitionedRegions.put(rootRegion, activeRegions);
// }
return partitionedTransformationAnalysis;
}
/**
* Remove the used connections whose consumers are necessarily after their last producer.
*/
protected void pruneRedundantConnections(@NonNull ConnectionManager connectionManager, @NonNull RootRegion rootRegion) {
List<@NonNull Connection> redundantConnections = null;
for (@NonNull Connection connection : QVTscheduleUtil.getOwnedConnections(rootRegion)) {
// String name = connection.getName();
if (!connection.isPassed() && !connection.isMandatory()) {
boolean isRedundant = true;
int lastPass = connection.getLastPass();
for (@NonNull Partition targetPartition : connection.getTargetPartitions()) {
int firstPass = targetPartition.getFirstPass();
if (firstPass <= lastPass) {
isRedundant = false;
break;
}
}
if (isRedundant) {
if (redundantConnections == null) {
redundantConnections = new ArrayList<>();
}
redundantConnections.add(connection);
}
}
}
if (redundantConnections != null) {
for (@NonNull Connection redundantConnection : redundantConnections) {
redundantConnection.destroy();
// connectionManager.removeTargetRegion(redundantConnection, scheduleManager.wipGetRegion(partition));
}
}
}
protected void schedule(@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis) {
RootPartitionAnalysis rootPartitionAnalysis = partitionedTransformationAnalysis.getRootPartitionAnalysis();
RootPartition rootPartition = rootPartitionAnalysis.getPartition();
RootRegion rootRegion = rootPartitionAnalysis.getRootRegion();
ConnectionManager connectionManager = scheduleManager.getConnectionManager();
List<@NonNull Concurrency> partitionSchedule = rootPartitionAnalysis.getPartitionSchedule();
//
// Create a connection between each consumer and the corresponding introducer/producer.
//
connectionManager.createConnections(rootRegion, partitionSchedule);
ScheduleAnalysis scheduleAnalysis = new ScheduleAnalysis(partitionedTransformationAnalysis, connectionManager, rootPartitionAnalysis);
scheduleAnalysis.schedule(rootPartition, partitionSchedule);
//
// Index all predicated and realized edges by typed model and property.
//
// partitionedTransformationAnalysis.analyzePartitionEdges(partitionSchedule);
List<Region> activeRegions = rootRegion.getActiveRegions();
activeRegions.clear();
List<@NonNull Concurrency> partitionSchedule1 = ConcurrentPartitionMerger.merge(partitionedTransformationAnalysis, rootPartitionAnalysis.getPartitionSchedule());
List<@NonNull Concurrency> partitionSchedule2 = SequentialPartitionMerger.merge(partitionedTransformationAnalysis, partitionSchedule1);
@SuppressWarnings("unused") List<@NonNull Concurrency> mergedPartitionSchedule = partitionSchedule2;
//
// Identify the input models.
//
computeInputModels();
//
// Identify the content of each region.
//
// PartitionedContentsAnalysis partitionedContentsAnalysis = connectionManager.getPartitionedContentsAnalysis();
// partitionedContentsAnalysis.analyzeRegions(rootPartition.getRootRegion());
//
// Create the root containment region to introduce all root and otherwise contained consumed classes.
//
createRootContainmentRegion(rootPartitionAnalysis);
List<@NonNull RootPartition> allRootPartitions = new ArrayList<>();
allRootPartitions.add(rootPartition);
//
// Remove the used connections whose consumers are necessarily after their last producer.
//
pruneRedundantConnections(connectionManager, rootRegion);
scheduleManager.writeDebugGraphs("8-pruned", true, true, false);
/* boolean noLateConsumerMerge = scheduleManager.isNoLateConsumerMerge();
if (!noLateConsumerMerge) {
List<@NonNull Collection<@NonNull Region>> regionSchedule = getRegionSchedule2(rootPartition, mergedPartitionSchedule); // FIXME separate side effects
lateMerge(rootPartition, regionSchedule, typedModel2property2predicatedEdges, typedModel2property2realizedEdges);
} */
// partitionedTransformationAnalysis.computeCheckedOrEnforcedEdges(mergedPartitionSchedule);
/* suspended - just an optimization - needs more hierarchical consideration
//
// Redirect ordered consumers to depend on each other's heads thereby respecting the ordering and
// making earlier results available to later mappings.
//
if (region2orderingEdge2usedEdges != null) {
for (@SuppressWarnings("null")@NonNull Region commonRegion : region2orderingEdge2usedEdges.keySet()) {
@SuppressWarnings("null")@NonNull Map<Edge, Set<Edge>> orderingEdge2usedEdges = region2orderingEdge2usedEdges.get(commonRegion);
convertConsumedOrdering(commonRegion, orderingEdge2usedEdges);
}
}
writeDOTfile("-5-reconsume");
writeGraphMLfile("-5-reconsume"); */
/* suspended - just an optimization - needs more hierarchical consideration
//
// Merge again now that dependencies may be available.
//
Region2Depth region2depths = new Region2Depth();
List<Region> sortedRegions = region2depths.getSortedRegions(getRegions());
for (Region calledRegion : sortedRegions) {
List<List<Node>> headNodeGroups = calledRegion.getHeadNodeGroups();
if ((headNodeGroups.size() == 1) && !(calledRegion instanceof LoadingRegion)) {
Region callingRegion = null;
boolean isMergeable = true;
for (Node headNode : headNodeGroups.get(0)) {
for (Node callingNode : headNode.getPassedBindingSources()) {
if (callingRegion == null) {
callingRegion = callingNode.getRegion();
}
else if (callingRegion != callingNode.getRegion()) {
isMergeable = false;
break;
}
}
}
if ((callingRegion != null) && isMergeable && callingRegion.isLateMergeable(calledRegion, region2depths)) {
Map<Node, Node> node2mergedNode = callingRegion.canMerge(calledRegion, region2depths, true);
if (node2mergedNode != null) {
MergedRegion mergedRegion;
if (callingRegion instanceof MergedRegion) {
mergedRegion = (MergedRegion)callingRegion;
}
else {
getRegions().remove(calledRegion);
mergedRegion = new MergedRegion((MergeableRegion)callingRegion);
Region invokingRegion = callingRegion.getInvokingRegion();
assert invokingRegion != null;
List<Region> regions = invokingRegion.getRegions();
int index = regions.indexOf(callingRegion);
assert index >= 0;
regions.set(index, mergedRegion);
// mergedRegion.writeDOTfile("-6-merged");
// mergedRegion.writeGraphMLfile("-6-merged");
}
mergedRegion.mergeRegion(calledRegion, node2mergedNode);
getRegions().remove(calledRegion);
mergedRegion.writeDOTfile("-6-merged");
mergedRegion.writeGraphMLfile("-6-merged");
mergedRegion.resolveRecursion();
mergedRegion.writeDOTfile("-7-merged");
mergedRegion.writeGraphMLfile("-7-merged");
region2depths.addRegion(mergedRegion);
}
}
}
} */
if (ConnectivityChecker.CONNECTIVITY.isActive()) {
// ConnectivityChecker.checkConnectivity(scheduleManager);
}
}
public @NonNull Iterable<@NonNull RootRegion> transform(@NonNull ScheduleManager scheduleManager, @NonNull Map<@NonNull RootRegion, Iterable<@NonNull MappingRegion>> rootRegion2activeRegions) throws CompilerChainException {
ConnectionManager connectionManager = scheduleManager.getConnectionManager();
LoadingRegion loadingRegion = loadingRegionAnalysis.getRegion();
Iterable<@NonNull RootRegion> rootRegions = rootRegion2activeRegions.keySet();
List<@NonNull PartitionedTransformationAnalysis> partitionedTransformationAnalyses = new ArrayList<>();
for (@NonNull RootRegion rootRegion : rootRegions) {
assert rootRegion.getActiveRegions().isEmpty();
Iterable<? extends @NonNull MappingRegion> activeRegions = rootRegion2activeRegions.get(rootRegion);
assert activeRegions != null;
List<@NonNull Region> activeRegions2 = new ArrayList<>();
activeRegions2.add(loadingRegion);
Iterables.addAll(activeRegions2, activeRegions);
Collections.sort(activeRegions2, NameUtil.NAMEABLE_COMPARATOR);
rootRegion.getActiveRegions().addAll(activeRegions2);
// RootPartition rootPartition = partition(scheduleManager, rootRegion, activeRegions2);
// rootPartitions.add(rootPartition);
//
// Create a connection between each consumer and the corresponding introducer/producer.
//
StringBuilder s = QVTscheduleConstants.CONNECTION_CREATION.isActive() ? new StringBuilder() : null;
for (@NonNull Region region : activeRegions2) {
if (!(region instanceof LoadingRegion)) {
connectionManager.createIncomingConnections(s, rootRegion, region);
}
}
if (s != null) {
QVTscheduleConstants.CONNECTION_CREATION.println(s.toString());;
}
}
UtilityAnalysis.assignUtilities(scheduleManager, loadingRegion);
scheduleManager.writeDebugGraphs("4-pre-partition", true, true, false);
scheduleManager.throwCompilerChainExceptionForErrors();
//
for (@NonNull RootRegion rootRegion : rootRegions) {
Iterable<@NonNull Region> activeRegions2 = QVTscheduleUtil.getActiveRegions(rootRegion);
PartitionedTransformationAnalysis partitionedTransformationAnalysis = partition(scheduleManager, rootRegion, activeRegions2);
partitionedTransformationAnalyses.add(partitionedTransformationAnalysis);
for (@NonNull Region region : QVTscheduleUtil.getActiveRegions(rootRegion)) {
connectionManager.createPartitionConnections(rootRegion, region);
}
}
// getRegionAnalysis(loadingRegion).setPartitions(Collections.singletonList(new NonPartition(loadingRegion));
scheduleManager.writeDebugGraphs("5-post-partition", true, true, false);
scheduleManager.throwCompilerChainExceptionForErrors();
//
for (@NonNull PartitionedTransformationAnalysis partitionedTransformationAnalysis : partitionedTransformationAnalyses) {
schedule(partitionedTransformationAnalysis);
}
scheduleManager.writeDebugGraphs("9-final", true, true, false);
return rootRegions;
}
}