Search code examples
pythondictionarygraphhypercube

Building a directed multigraph (Python)


Lets say I get one list which represents the weights to adjacent nodes. The multigraph is shaped like a hypercube. The nodes will be named by their coordinates as a binary string.

En example for n=3

bin_string = ['000', '100', '010', '001', '110', '101', '011', '111']
weights = [[-5, -13, -2], [16, -9], [-15, 2], [13, -13], [18], [-9], [18]]

I want to build a dictionary from both lists in the following way: We start at 000 and have edges to all nodes with one 1 more in reversed lexicographic order (like in bin_string). The second node would be 100 (one 1 more, biggest first) and that node can have edges to all nodes with, again, one 1 more. So the dictionary would look like this:

d = { '000':{'100':-5, '010':-13, '001':-2},
      '100':{'110':16, '101':-9},
      '010':{'110':-15, '011':2},
      '001':{'101':13, '011':-13},
      '110':{'111':18},
      '101':{'111':-9},
      '011':{'111':18}
     }

I have hypercubes with all kinds of dimensions and can already generate bin_string depending on the dimension. But how do I marry bin_string and weights to one dictionary?


Solution

  • Python dictionaries have no defined order, so you'll need to use collections.OrderedDict. Here's an example:

    from collections import OrderedDict
    
    def one_more_one(s):
        for i, digit in enumerate(s):
            if digit == '0':
                yield s[:i] + '1' + s[i+1:]
    
    bin_string = ['000', '100', '010', '001', '110', '101', '011', '111']
    weights = [[-5, -13, -2], [16, -9], [-15, 2], [13, -13], [18], [-9], [18]]
    
    d = OrderedDict()
    for node, weight in zip(bin_string, weights):
        d[node] = OrderedDict(zip(one_more_one(node), weight))
    

    Here, one_more_one is a generator yielding the neighbors of a node which have "one more one". It yields them in reverse lexicographic order.

    If order isn't important, you can just use normal python dicts. You can recover a normal dict by writing:

    {k:dict(v) for k,v in d.iteritems()}
    

    which gives

    {'000': {'001': -2, '010': -13, '100': -5},
     '001': {'011': -13, '101': 13},
     '010': {'011': 2, '110': -15},
     '011': {'111': 18},
     '100': {'101': -9, '110': 16},
     '101': {'111': -9},
     '110': {'111': 18}}