'Adds a new node only if it doesn\'t already exist.
:param source_id: the id of the source node
:type source_id: (hashable)
:param target_id: the id of the target node
:type target_id: (hashable)
:param data: any extra data that needs to be saved for the edge
:type data: (variadic dictionary)
:returns: the new node
..note: that, although this will create new nodes if necessary, there\'s
no way to pass `data` to them - so if you need to assoc. more data with
the nodes, use `add_node` first.'

def add_edge(self, source_id, target_id, **data):

    if (source_id not in self.nodes):
        self.add_node(source_id)
    if (target_id not in self.nodes):
        self.add_node(target_id)
    new_edge = SimpleGraphEdge(self.nodes[source_id].index, self.nodes[target_id].index, **data)
    self.edges.append(new_edge)
    return new_edge
