.. _linkage-py: ########## linkage.py ########## ********************** class Linkage(object): ********************** The complete object linking for the data matrix. For each object linking to all other objects in the data hierarchy lineage is stored as a set of object indices by data level. def __init__(self, hierarchy): ============================== Attributes: - hierarchy: a dictionary with level indices as keys. The data is a dictionary with 'ordinal' and 'lineage' as keys. - ordinal contains the ordinal number of of the data level in the data hierarchy starting from 0 for the root data level. - lineage contains a set of lineage identifiers for the data level: .. image:: ../../../docs/manual/img/lineage.png In the figure there is only a single lineage in the a) case as there is only one sub level for each data level. In the b) case the root level has two different sub levels and hence there are two lineages in the data hierarchy. The black nodes belong to the lineage 0 and the white nodes belong to the lineage 1. However, the root node is an exception to this rule as it belongs to both lineages 0 and 1 being the parent level for both. - links: {(iteration, branch):{(level index, object index):}} - link dict: level indices as key and a set of object indices as data. The set contains the object indices to which the object identified by the combination key of (simulation unit, branch)(level index, object index) is connected to :: >>> hierarchy = {0: {'ordinal':0, 'lineage':set([0, 1])}, ... 1: {'ordinal':1, 'lineage':set([0])}, ... 2: {'ordinal':1, 'lineage':set([1])}, ... 3: {'ordinal':2, 'lineage':set([0])}, ... 4: {'ordinal':2, 'lineage':set([1])}} >>> from simo.matrix.linkage import Linkage >>> l = Linkage() def add_object(self, hierarchy, iteration, branch, objkey, parentkey, update_existing=True): ============================================================================================ Add linking information for a new object and all nodes connected to it. Test data here is for the b-case in the figure; i.e., five different data levels, level 0 being the root level having two child levels 1 and 2. Level 3 is the child of level 1 and level 4 the child of level 2. In the data structure the first key indicates the iteration and branch, and the second tuple the data level and object index, while the third is the data level and object index of the parent node:: >>> data = [(0, (0, 0), (None, None)), (0, (1, 0), (0, 0)), ... (0, (2, 0), (0, 0)), (0, (3, 0), (1, 0)), ... (0, (4, 1), (2, 0)), (0, (4, 2), (2, 0)), ... (0, (4, 0), (2, 0))] >>> iteration = 0 >>> for node in data: ... branch, objkey, parentkey = node ... l.add_object(hierarchy, iteration, branch, objkey, parentkey) >>> l.links[(0, 0)][(0, 0)] {1: [0], 2: [0], 3: [0], 4: [0, 1, 2]} >>> l.links[(0, 0)][(1, 0)] {0: [0], 3: [0]} >>> l.links[(0, 0)][(2, 0)] {0: [0], 4: [0, 1, 2]} >>> l.links[(0, 0)][(3, 0)] {0: [0], 1: [0]} >>> l.links[(0, 0)][(4, 0)] {0: [0], 2: [0]} >>> l.links[(0, 0)][(4, 1)] {0: [0], 2: [0]} >>> l.links[(0, 0)][(4, 2)] {0: [0], 2: [0]} Construct another linkage for testing adding object relations between existing objects. >>> l2 = Linkage() >>> data = [(0, (0, 0), (None, None)), (0, (2, 0), (0, 0)), ... (0, (2, 1), (0, 0)), (0, (2, 2), (0, 0)), ... (0, (1, 0), (0, 0)), (0, (1, 1), (0, 0)),] >>> for node in data: ... branch, objkey, parentkey = node ... l2.add_object(hierarchy, 0, 0, objkey, parentkey) >>> l2.links[(0, 0)][(0, 0)] {1: [0, 1], 2: [0, 1, 2]} >>> l2.links[(0, 0)][(2, 0)] {0: [0]} Add objects without updating existing linkage info. This is needed when adding object relations between existing objects instead of new objects (when for example creating new objects by grouping existing objects):: >>> l2.add_object(hierarchy, 0, 0, (2, 0), (1, 0), False) >>> l2.add_object(hierarchy, 0, 0, (2, 1), (1, 0), False) >>> l2.add_object(hierarchy, 0, 0, (2, 2), (1, 1), False) >>> l2.links[(0, 0)][(0, 0)] {1: [0, 1], 2: [0, 1, 2]} >>> l2.links[(0, 0)][(1, 0)] {0: [0], 2: [0, 1]} >>> l2.links[(0, 0)][(1, 1)] {0: [0], 2: [2]} >>> l2.links[(0, 0)][(2, 0)] {0: [0], 1: [0]} >>> l2.links[(0, 0)][(2, 1)] {0: [0], 1: [0]} >>> l2.links[(0, 0)][(2, 2)] {0: [0], 1: [1]} def remove_object(self, simobj, obj, children=False): ===================================================== Remove the references to the object from all the connected nodes, and the object from the links structure:: >>> l.links[(0, 0)][(1, 0)] {0: [0], 3: [0]} >>> l.links[(0, 0)][(2, 0)] {0: [0], 4: [0, 1, 2]} >>> l.links[(0, 0)][(3, 0)] {0: [0], 1: [0]} >>> l.links[(0, 0)][(4, 0)] {0: [0], 2: [0]} >>> l.remove_object(0, 0, (4, 0)) {4: [0]} >>> l.links[(0, 0)][(2, 0)] {0: [0], 4: [1, 2]} Child removal can be forced with children-parameter:: >>> l.remove_object(0, 0, (2, 0), children=True) {2: [0], 4: [1, 2]} >>> l.links[(0, 0)][(0, 0)] {1: [0], 3: [0]}