CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
604 lines
21 KiB
Python
604 lines
21 KiB
Python
################################################################################
|
|
#
|
|
# Copyright (C) 2019-2024 Advanced Micro Devices, Inc. All rights reserved.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
#
|
|
################################################################################
|
|
|
|
import itertools
|
|
import re
|
|
|
|
from . import Properties
|
|
from . import Hardware
|
|
from . import Common
|
|
from . import Contractions
|
|
from .SolutionStructs import Solution as OriginalSolution
|
|
from .Utils import state
|
|
|
|
class SingleSolutionLibrary:
|
|
Tag = "Single"
|
|
|
|
# allow null solution. This enables the solution library to have
|
|
# an effective default value when the related field in the logic
|
|
# file is optional.
|
|
def __init__(self, solution = None):
|
|
self.solution = solution
|
|
|
|
@property
|
|
def tag(self):
|
|
return self.__class__.Tag
|
|
|
|
def state(self):
|
|
# handles the case when the solution is null.
|
|
# -1 index represents null solution.
|
|
if self.solution:
|
|
return {"type": self.tag, "index": self.solution.index}
|
|
else:
|
|
return {"type": self.tag, "index": -1}
|
|
|
|
def remapSolutionIndices(self, indexMap):
|
|
pass
|
|
|
|
class IndexSolutionLibrary(SingleSolutionLibrary):
|
|
Tag = "Index"
|
|
|
|
def state(self):
|
|
return self.solution.index
|
|
|
|
|
|
class PlaceholderLibrary:
|
|
Tag = 'Placeholder'
|
|
|
|
def __init__(self, name):
|
|
self.filenamePrefix = name
|
|
|
|
@property
|
|
def tag(self):
|
|
return self.__class__.Tag
|
|
|
|
def state(self):
|
|
return {'type': self.tag, 'value': self.filenamePrefix}
|
|
|
|
def remapSolutionIndices(self, indexMap):
|
|
pass
|
|
|
|
def merge(self, other):
|
|
pass
|
|
|
|
|
|
class MatchingLibrary:
|
|
Tag = "Matching"
|
|
StateKeys = [("type", "tag"), "properties", "table", "distance"]
|
|
|
|
@classmethod
|
|
def FromOriginalState(cls, d, solutions):
|
|
indices = d["indexOrder"]
|
|
distance = d["distance"]
|
|
origTable = d["table"]
|
|
|
|
propertyKeys = {
|
|
2: Properties.Property("FreeSizeA", index=0),
|
|
3: Properties.Property("FreeSizeB", index=0),
|
|
1: Properties.Property("BoundSize", index=0)
|
|
}
|
|
if distance == "Equality":
|
|
propertyKeys[0] = Properties.Property("BatchSize", index=0)
|
|
|
|
properties = list([propertyKeys[i] for i in indices if i in propertyKeys])
|
|
keyOrder = [i for i, j in enumerate(indices) if j in propertyKeys]
|
|
|
|
table = []
|
|
|
|
for row in origTable:
|
|
try:
|
|
index = row[1][0]
|
|
value = IndexSolutionLibrary(solutions[index])
|
|
key = list([row[0][i] for i in keyOrder])
|
|
if distance == "GridBased":
|
|
entry = {"key": key, "index": value}
|
|
else:
|
|
entry = {"key": key, "index": value, "speed": row[1][1]}
|
|
|
|
table.append(entry)
|
|
except KeyError:
|
|
pass
|
|
|
|
table.sort(key=lambda r: r["key"])
|
|
|
|
return cls(properties, table, distance)
|
|
|
|
@property
|
|
def tag(self):
|
|
return self.__class__.Tag
|
|
|
|
def merge(self, other):
|
|
assert self.__class__ == other.__class__ \
|
|
and self.properties == other.properties \
|
|
and self.distance == other.distance
|
|
|
|
self.table += other.table
|
|
|
|
self.table.sort(key=lambda r: r["key"])
|
|
|
|
def remapSolutionIndices(self, indexMap):
|
|
pass
|
|
|
|
def __init__(self, properties, table, distance):
|
|
self.properties = properties
|
|
self.table = table
|
|
self.distance = distance
|
|
|
|
|
|
class DecisionTreeLibrary:
|
|
Tag = "DecisionTree"
|
|
StateKeys = [("type", "tag"), "features", "trees", "nullValue"]
|
|
|
|
@classmethod
|
|
def FromOriginalState(cls, d, solutions):
|
|
features = d["features"]
|
|
origTrees = d["trees"]
|
|
|
|
# Support for legacy implementation of the dtree which has no fallback.
|
|
if "fallback" in d:
|
|
fallbackIndex = d["fallback"]
|
|
nullValue = SingleSolutionLibrary(solutions[fallbackIndex])
|
|
else:
|
|
# The default solution is null
|
|
nullValue = SingleSolutionLibrary()
|
|
|
|
trees = []
|
|
|
|
for tree in origTrees:
|
|
index = tree["solution"]
|
|
value = SingleSolutionLibrary(solutions[index])
|
|
|
|
entry = {"tree": tree["tree"], "value": value}
|
|
trees.append(entry)
|
|
|
|
return cls(features, trees, nullValue)
|
|
|
|
@property
|
|
def tag(self):
|
|
return self.__class__.Tag
|
|
|
|
def merge(self, other):
|
|
raise RuntimeError(
|
|
"DecisionTreeLibrary does not support merging; ensure each library row has a unique predicate"
|
|
)
|
|
|
|
def remapSolutionIndices(self, indexMap):
|
|
pass
|
|
|
|
def __init__(self, features, trees, nullValue):
|
|
self.features = features
|
|
self.trees = trees
|
|
self.nullValue = nullValue
|
|
|
|
|
|
class ProblemMapLibrary:
|
|
Tag = "ProblemMap"
|
|
StateKeys = [("type", "tag"), ("property", "mappingProperty"), ("map", "mapping")]
|
|
|
|
def __init__(self, mappingProperty=None, mapping=None):
|
|
self.mappingProperty = mappingProperty
|
|
self.mapping = mapping
|
|
|
|
@property
|
|
def tag(self):
|
|
return self.__class__.Tag
|
|
|
|
def merge(self, other):
|
|
assert self.__class__ == other.__class__ and self.tag == other.tag and self.mappingProperty == other.mappingProperty
|
|
|
|
for key, value in list(other.mapping.items()):
|
|
if key in self.mapping:
|
|
self.mapping[key].merge(value)
|
|
else:
|
|
self.mapping[key] = value
|
|
|
|
def remapSolutionIndices(self, indexMap):
|
|
for key, value in list(self.mapping.items()):
|
|
value.remapSolutionIndices(indexMap)
|
|
|
|
|
|
class PredicateLibrary:
|
|
StateKeys = [("type", "tag"), "rows"]
|
|
|
|
def __init__(self, tag=None, rows=None):
|
|
self.tag = tag
|
|
if rows is None: rows = []
|
|
self.rows = rows
|
|
|
|
def merge(self, other):
|
|
assert self.__class__ == other.__class__ and self.tag == other.tag
|
|
|
|
rowPreds = [r["predicate"] for r in self.rows]
|
|
|
|
for row in other.rows:
|
|
if row["predicate"] in rowPreds:
|
|
myRownum = rowPreds.index(row["predicate"])
|
|
self.rows[myRownum]["library"].merge(row["library"])
|
|
else:
|
|
self.rows.append(row)
|
|
|
|
# Sort to ensure consistent fallback logic.
|
|
self.rows.sort(key=lambda x: x["predicate"])
|
|
|
|
def remapSolutionIndices(self, indexMap):
|
|
for row in self.rows:
|
|
row["library"].remapSolutionIndices(indexMap)
|
|
|
|
|
|
class MasterSolutionLibrary:
|
|
StateKeys = ["solutions", "library"]
|
|
ArchitectureSet = set()
|
|
|
|
@classmethod
|
|
def ArchitectureIndexMap(cls, architectureName: str) -> int:
|
|
"""Maps hex characters from gfx name to an index.
|
|
|
|
Given a gfx name of the form gfx[0-9a-f]*, map the characters following
|
|
gfx from hex to int and left shift the integer by 18.
|
|
|
|
Args:
|
|
architectureName: The gfx name (or fallback).
|
|
|
|
Returns:
|
|
An integer representing the index for the given gfx architecture.
|
|
|
|
Raises:
|
|
RunTimeError: The provided architecture was already mapped to an index or umappable.
|
|
"""
|
|
archval = -1
|
|
if architectureName == "fallback":
|
|
archval = 0
|
|
elif architectureName.startswith("gfx"):
|
|
archString = re.search('(?<=gfx)[0-9a-f]*', architectureName)
|
|
if archString is not None:
|
|
archLiteral = archString.group(0)
|
|
archval = (int(archLiteral, 16) << 18)
|
|
# Check for duplicate architecture values
|
|
if archval >= 0 and not archval in cls.ArchitectureSet:
|
|
cls.ArchitectureSet.add(archval)
|
|
else:
|
|
raise RuntimeError("ERROR in architecture solution index mapping.")
|
|
return archval
|
|
|
|
@classmethod
|
|
def FixSolutionIndices(cls, solutions):
|
|
# fix missing and duplicate solution indices.
|
|
try:
|
|
maxSolutionIdx = max([s.index for s in solutions if s.index is not None])
|
|
except ValueError:
|
|
maxSolutionIdx = -1
|
|
|
|
solutionsSoFar = set()
|
|
for solution in solutions:
|
|
if solution.index is None or solution.index in solutionsSoFar:
|
|
maxSolutionIdx += 1
|
|
solution.index = maxSolutionIdx
|
|
else:
|
|
solutionsSoFar.add(solution.index)
|
|
|
|
@classmethod
|
|
def FromOriginalState(cls,
|
|
origData,
|
|
origSolutions,
|
|
solutionClass=Contractions.Solution,
|
|
libraryOrder=None):
|
|
|
|
# functions for creating each "level" of the library
|
|
def hardware(d, problemType, solutions, library, placeholderName):
|
|
devicePart = d["ArchitectureName"]
|
|
cuCount = d["CUCount"]
|
|
isAPU = d["IsAPU"]
|
|
|
|
newLib = PredicateLibrary(tag="Hardware")
|
|
if devicePart == "fallback":
|
|
pred = Hardware.HardwarePredicate("TruePred")
|
|
else:
|
|
pred = Hardware.HardwarePredicate.FromHardware(Common.gfxArch(devicePart), cuCount, isAPU)
|
|
|
|
newLib.rows.append({"predicate": pred, "library": library})
|
|
|
|
if lazyLibrary:
|
|
if cuCount:
|
|
placeholderName += "_CU" + str(cuCount)
|
|
if isAPU is not None:
|
|
placeholderName += "_APU" if isAPU == 1 else "_XPU"
|
|
placeholderName += "_" + str(devicePart)
|
|
|
|
return newLib, placeholderName
|
|
|
|
def operationIdentifier(d, problemType, solutions, library, placeholderName):
|
|
operationID = problemType.operationIdentifier
|
|
prop = Properties.Property("OperationIdentifier")
|
|
mapping = {operationID: library}
|
|
|
|
newLib = ProblemMapLibrary(prop, mapping)
|
|
|
|
if lazyLibrary:
|
|
placeholderName += "_" + operationID
|
|
|
|
return newLib, placeholderName
|
|
|
|
def performanceMetric(d, problemType, solutions, library, placeholderName):
|
|
if d.get("PerfMetric", "DeviceEfficiency") != "DeviceEfficiency":
|
|
predicate = Properties.Predicate(tag=d["PerfMetric"])
|
|
else:
|
|
predicate = Properties.Predicate(tag="TruePred")
|
|
newLib = PredicateLibrary(tag="Problem")
|
|
newLib.rows.append({"predicate": predicate, "library": library})
|
|
|
|
if lazyLibrary and predicate.tag != "TruePred":
|
|
placeholderName += "_" + predicate.tag
|
|
|
|
return newLib, placeholderName
|
|
|
|
def fp16AltImpl(d, problemType, solutions, library, placeholderName):
|
|
if d.get("Fp16AltImpl"):
|
|
predicate = Properties.Predicate(tag="Fp16AltImpl")
|
|
else:
|
|
predicate = Properties.Predicate(tag="TruePred")
|
|
newLib = PredicateLibrary(tag="Problem")
|
|
newLib.rows.append({"predicate": predicate, "library": library})
|
|
|
|
if lazyLibrary and predicate.tag == "Fp16AltImpl" and not d.get("Fp16AltImplRnz"):
|
|
placeholderName += "_Fp16Alt"
|
|
|
|
return newLib, placeholderName
|
|
|
|
def fp16AltImplRound(d, problemType, solutions, library, placeholderName):
|
|
if d.get("Fp16AltImplRound"):
|
|
predicate = Properties.Predicate(tag="Fp16AltImplRound")
|
|
else:
|
|
predicate = Properties.Predicate(tag="TruePred")
|
|
newLib = PredicateLibrary(tag="Problem")
|
|
newLib.rows.append({"predicate": predicate, "library": library})
|
|
|
|
if lazyLibrary and predicate.tag == "Fp16AltImplRound":
|
|
placeholderName += "_Fp16AltRnz"
|
|
|
|
return newLib, placeholderName
|
|
|
|
def predicates(d, problemType, solutions, library, placeholderName):
|
|
predicates = problemType.predicates(includeBatch=True, includeType=True)
|
|
predicate = Contractions.ProblemPredicate.And(predicates)
|
|
|
|
newLib = PredicateLibrary(tag="Problem")
|
|
newLib.rows.append({"predicate": predicate, "library": library})
|
|
|
|
if lazyLibrary:
|
|
placeholderName += problemType.placeholderStr(includeBatch=True, includeType=True)
|
|
|
|
return newLib, placeholderName
|
|
|
|
def placeholder(d, problemType, solutions, library, placeholderName):
|
|
newLib = PlaceholderLibrary(placeholderName)
|
|
return newLib, placeholderName
|
|
|
|
def selection(d, problemType, solutions, library, placeholderName):
|
|
if d["LibraryType"] == "Matching":
|
|
if d["Library"]["distance"] == "Equality":
|
|
predicate = Properties.Predicate(tag="EqualityMatching")
|
|
else:
|
|
predicate = Properties.Predicate(tag="TruePred")
|
|
|
|
matchingLib = MatchingLibrary.FromOriginalState(d["Library"], solutions)
|
|
library = PredicateLibrary(tag="Problem")
|
|
library.rows.append({"predicate": predicate, "library": matchingLib})
|
|
|
|
elif d["LibraryType"] == "DecisionTree":
|
|
library = PredicateLibrary(tag="Problem")
|
|
for lib in d["Library"]:
|
|
preds = lib["region"]
|
|
predObjs = [Properties.Predicate.FromOriginalState(p) for p in preds]
|
|
|
|
if len(predObjs) == 1:
|
|
predicate = predObjs[0]
|
|
else:
|
|
predicate = Properties.Predicate.And(predObjs)
|
|
|
|
treeLib = DecisionTreeLibrary.FromOriginalState(lib, solutions)
|
|
library.rows.append({"predicate": predicate, "library": treeLib})
|
|
|
|
return library, placeholderName
|
|
|
|
# end library creation functions
|
|
|
|
if libraryOrder is None:
|
|
if Common.globalParameters["LazyLibraryLoading"]:
|
|
libraryOrder = [
|
|
hardware, operationIdentifier, performanceMetric, fp16AltImpl, fp16AltImplRound, predicates,
|
|
placeholder, selection
|
|
]
|
|
else:
|
|
libraryOrder = [
|
|
hardware, operationIdentifier, performanceMetric, fp16AltImpl, fp16AltImplRound, predicates,
|
|
selection
|
|
]
|
|
#assert libraryOrder[-1] == selection
|
|
|
|
lazyLibrary = None
|
|
if placeholder in libraryOrder:
|
|
placeholderIndex = libraryOrder.index(placeholder) + 1
|
|
lazyLibrary = MasterSolutionLibrary.FromOriginalState(origData, origSolutions,
|
|
solutionClass,
|
|
libraryOrder[placeholderIndex:])
|
|
libraryOrder = libraryOrder[0:placeholderIndex]
|
|
origSolutions = []
|
|
|
|
problemType = Contractions.ProblemType.FromOriginalState(origData["ProblemType"])
|
|
allSolutions = [solutionClass.FromSolutionStruct(s) for s in origSolutions]
|
|
cls.FixSolutionIndices(allSolutions)
|
|
|
|
# library is constructed in reverse order i.e. bottom-up
|
|
library = None
|
|
placeholderName = "TensileLibrary"
|
|
placeholderLibrary = None
|
|
for libName in reversed(libraryOrder):
|
|
library, placeholderName = libName(origData, problemType, allSolutions, library,
|
|
placeholderName)
|
|
if libName == placeholder:
|
|
placeholderLibrary = library
|
|
|
|
solutions = {s.index: s for s in allSolutions}
|
|
rv = cls(solutions, library)
|
|
if lazyLibrary and placeholderLibrary:
|
|
rv.lazyLibraries[placeholderName] = lazyLibrary
|
|
placeholderLibrary.filenamePrefix = placeholderName
|
|
|
|
return rv
|
|
|
|
@classmethod
|
|
def BenchmarkingLibrary(cls, solutions):
|
|
solutionObjs = list([Contractions.Solution.FromOriginalState(s.getAttributes()) for s in solutions])
|
|
cls.FixSolutionIndices(solutionObjs)
|
|
|
|
predRows = list([{
|
|
"predicate": s.problemPredicate,
|
|
"library": SingleSolutionLibrary(s)
|
|
} for s in solutionObjs])
|
|
library = PredicateLibrary(tag="Problem", rows=predRows)
|
|
|
|
solutionMap = {s.index: s for s in solutionObjs}
|
|
|
|
return cls(solutionMap, library)
|
|
|
|
def __init__(self, solutions, library, version=None):
|
|
self.lazyLibraries = {}
|
|
self.solutions = solutions
|
|
self.library = library
|
|
self.version = version
|
|
|
|
def state(self):
|
|
rv = {
|
|
"solutions": state(iter(list(self.solutions.values()))),
|
|
"library": state(self.library)
|
|
}
|
|
|
|
if self.version is not None:
|
|
rv["version"] = self.version
|
|
return rv
|
|
|
|
def applyNaming(self, naming=None):
|
|
if naming is None:
|
|
#allSolutions = itertools.chain(iter(list(self.solutions.values())), iter(list(self.sourceSolutions.values())))
|
|
kernels = list(
|
|
itertools.chain(*[s.originalSolution.getKernels()
|
|
for s in self.solutions.values()]))
|
|
naming = OriginalSolution.getMinNaming(kernels)
|
|
|
|
for s in list(self.solutions.values()):
|
|
s.name = OriginalSolution.getNameMin(s.originalSolution.getKernels(), naming)
|
|
|
|
def _remapSolutionIndicesStartingFrom(self, library, solutions: dict, curIndex: int) -> tuple:
|
|
reIndexMap = {}
|
|
newSolutions = {}
|
|
for _, soln in solutions.items():
|
|
reIndexMap[soln.index] = curIndex
|
|
soln.index = curIndex
|
|
newSolutions[curIndex] = soln
|
|
curIndex += 1
|
|
return newSolutions, reIndexMap
|
|
|
|
def remapSolutionIndicesStartingFrom(self, startingIndex) -> None:
|
|
"""Remap all the solution indexes for a given library.
|
|
|
|
Given a starting index, remap all indexes for a given library
|
|
including the lazy libraries if enabled. If a library has five
|
|
solutions and the starting index is 222, the solution.index fields
|
|
would be 222, 223, 224, 225 and 226 respectively. If there are two
|
|
lazy libraries and each have two solutions, the solution.index
|
|
fields would be 222, 223, 224 and 225 respectively.
|
|
|
|
Args:
|
|
startingIndex: The index to start remapping from.
|
|
"""
|
|
if self.lazyLibraries:
|
|
lazyLibrary = {}
|
|
for name, lib in self.lazyLibraries.items():
|
|
lib.solutions, reIndexMap = self._remapSolutionIndicesStartingFrom(lib.library, lib.solutions, startingIndex)
|
|
lib.library.remapSolutionIndices(reIndexMap)
|
|
lazyLibrary[name] = lib
|
|
self.lazyLibraries = lazyLibrary
|
|
|
|
self.solutions, reIndexMap = self._remapSolutionIndicesStartingFrom(self.library, self.solutions, startingIndex)
|
|
self.library.remapSolutionIndices(reIndexMap)
|
|
|
|
def insert(self, other):
|
|
assert self.__class__ == other.__class__
|
|
|
|
for name, lib in other.lazyLibraries.items():
|
|
self.lazyLibraries[name] = lib
|
|
|
|
for _, s in other.solutions.items():
|
|
self.solutions[s.index] = s
|
|
self.library.merge(other.library)
|
|
|
|
def merge(self, other, startIndex=0):
|
|
assert self.__class__ == other.__class__
|
|
|
|
curIndex = max(startIndex, max(self.solutions.keys()) + 1 if self.solutions else 0)
|
|
if self.lazyLibraries:
|
|
curIndex = max(
|
|
curIndex,
|
|
max(max(lib.solutions.keys()) for _, lib in self.lazyLibraries.items()) + 1)
|
|
|
|
#Merge separate library files
|
|
for name, lib in other.lazyLibraries.items():
|
|
if name in self.lazyLibraries.keys():
|
|
curIndex = self.lazyLibraries[name].merge(lib, curIndex)
|
|
else:
|
|
reIndexMap = {}
|
|
newSolutions = {}
|
|
|
|
for k, s in lib.solutions.items():
|
|
reIndexMap[s.index] = curIndex
|
|
s.index = curIndex
|
|
newSolutions[curIndex] = s
|
|
curIndex += 1
|
|
|
|
lib.solutions = newSolutions
|
|
lib.library.remapSolutionIndices(reIndexMap)
|
|
|
|
self.lazyLibraries[name] = lib
|
|
|
|
reIndexMap = {}
|
|
for k, s in other.solutions.items():
|
|
reIndexMap[s.index] = curIndex
|
|
s.index = curIndex
|
|
self.solutions[curIndex] = s
|
|
curIndex += 1
|
|
|
|
other.library.remapSolutionIndices(reIndexMap)
|
|
|
|
self.library.merge(other.library)
|
|
|
|
return curIndex #Next unused index
|
|
|
|
@property
|
|
def cpp_base_class(self):
|
|
return "SolutionLibrary<ContractionProblem, ContractionSolution>"
|
|
|
|
@property
|
|
def cpp_class(self):
|
|
return "MasterSolutionLibrary<ContractionProblem, ContractionSolution>"
|