How to generate all directed permutations of an undirected graph? - python

I am looking for a way to generate all possible directed graphs from an undirected template. For example, given this graph "template":
I want to generate all six of these directed versions:
In other words, for each edge in the template, choose LEFT, RIGHT, or BOTH direction for the resulting edge.
There is a huge number of outputs for even a small graph, because there are 3^E valid permutations (where E is the number of edges in the template graph), but many of them are duplicates (specifically, they are automorphic to another output). Take these two, for example:
I only need one.
I'm curious first: Is there is a term for this operation? This must be a formal and well-understood process already?
And second, is there a more efficient algorithm to produce this list? My current code (Python, NetworkX, though that's not important for the question) looks like this, which has two things I don't like:
I generate all permutations even if they are isomorphic to a previous graph
I check isomorphism at the end, so it adds additional computational cost
Results := Empty List
T := The Template (Undirected Graph)
For i in range(3^E):
Create an empty directed graph G
convert i to trinary
For each nth edge in T:
If the nth digit of i in trinary is 1:
Add the edge to G as (A, B)
If the nth digit of i in trinary is 2:
Add the edge to G as (B, A)
If the nth digit of i in trinary is 0:
Add the reversed AND forward edges to G
For every graph in Results:
If G is isomorphic to Results, STOP
Add G to Results

Related

topological sort of a graph with emphasis on depth first seach and a given order of out edges

I have a directed acyclic graph and have specific requirements on the topological sort:
Depth first search: I want each branch to reach an end before a new branch is added to the sorting
Several nodes have multiple outgoing edges. For those nodes I have a sorted list of successor nodes, that is to be used in choosing with which node to continue the sorting.
Example:
When the node n is reached, that has three successors m1, m2, m3 of which each one of them would be a valid option to continue, I would provide a list such as [m3, m1, m2] that would indicate to continue with the node m3.
I am using networkx. I thought about iterating through the nodes with
sorting = []
for n in dfs_edges(dag, source = 'root'):
sorting.append(n[0])
Or using the method dfs_preorder_nodes but I have not found a way to make it use the list.
Any hints?

Finding Clique using graph and vertices

PYTHON ONLY!!
I have a graph
graph = [[0,1,1,1,0],
[1,0,0,0,0],
[0,1,0,1,1],
[1,0,1,0,1],
[0,0,1,1,0]]
The function clique(graph, vertices) should take an adjacency matrix
representation of a graph, a list of one or more vertices, and return a boolean True if the vertices create a clique
(every person is friends with every other person), otherwise return False.
`def clique(graph, vertices)`
I want to find out whether does a clique exists in the graph above
If yes the output should be True, otherwise False
eg. 'clique', (graph,[2,3,4]), True)]
Explanation needed thanks!
https://en.wikipedia.org/wiki/Clique_problem
Here you go, depending on what problem you ACTUALLY want to solve, here you have a starting point for finding an algorithm.
Is a graph a clique: Just check that all nodes are adjacent to each other.
Does it contain a clique? Always true if the graph is non-empty because a single vertex is already a clique of size one.
Does it contain a clique of size k? brute force it
Find a single maximal clique? Greedy algorithm possible as described in the link.
Find all maximal cliques? see wikipedia page for references (this is hard)

python networkx get unique matching combinations

I have a graph of nodes that are potential duplicates of items and I'm trying to find all possible combinations of matches. If two nodes are connected, that means they are potentially the same item, but no node can be matched more than once.
For example, if I take the following simple graph:
T = nx.Graph()
T.add_edge('A','B')
T.add_edge('A','C')
T.add_edge('B','D')
T.add_edge('D','A')
In this example my outputs could either be:
[{A:B},{A:C,B:D},{A:D}]
How can I develop a list of unique combinations? Some of the graphs have ~20 nodes, so brute forcing through all combinations is out.
It seems that what you are looking for is to find matchings of G, i.e., sets of edges where no two edges share a common vertex.
In particular, you are looking for maximal matchings of G.
Networkx offers the function maximal_matching. You may extend this function to obtain all the maximal matchings.
One way to do it may be the following. You start with a list of partial matchings, each made by an edge. Each partial matching is then extended until it becomes a maximal one, i.e., until it cannot be extended to a matching of larger cardinality.
If a partial matching m can be extended to a larger one using an edge (u,v), then m'=m ∪ {(u,v)} is added to the list of partial matchings. Otherwise, m is added to the list of maximal matchings.
The following code can be improved to be more efficient in many ways. One way is to check before adding to the list of partial matchings. indeed, the list will contain partial matchings which represent the same one (i.e., [{i,j},{u,v}] and [{u,v},{i,j}] ).
import networkx as nx
import itertools
def all_maximal_matchings(T):
maximal_matchings = []
partial_matchings = [{(u,v)} for (u,v) in T.edges()]
while partial_matchings:
# get current partial matching
m = partial_matchings.pop()
nodes_m = set(itertools.chain(*m))
extended = False
for (u,v) in T.edges():
if u not in nodes_m and v not in nodes_m:
extended = True
# copy m, extend it and add it to the list of partial matchings
m_extended = set(m)
m_extended.add((u,v))
partial_matchings.append(m_extended)
if not extended and m not in maximal_matchings:
maximal_matchings.append(m)
return maximal_matchings
T = nx.Graph()
T.add_edge('A','B')
T.add_edge('A','C')
T.add_edge('B','D')
T.add_edge('D','A')
print(all_maximal_matchings(T))

Best way to represent a graph to be stored in a text file [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
My problem involves creating a directed graph, checking if it unique by comparing to a text file containing graphs and if it is unique, appending it to the file. What would be the best representation of graph to be used in that case?
I'm using Python and I'll be using brute-force to check if graphs are isomorphic, since the graphs are small and have some restrictions.
There is a standard text based format called DOT which allows you to work with directed and undirected graphs, and would give you the benefit of using a variety of different libraries to work with your graphs. Notably graphviz which allows you to read and write DOT files, as well as plot them graphically using matplotlib.
Assuming that this is a simple case of how the graphs are represented you might be ok with a simple CSV format where a line is a single edge and ther's some separator between graphs, eg:
graph_4345345
A,B
B,C
C,E
E,B
graph_3234766
F,D
B,C
etc.
You could then make use of https://docs.python.org/3/library/csv.html
I guess it depends on how you are going to represent your graph as a data structure.
The two most known graph representations as data structures are:
Adjacency matrices
Adjacency lists
Adjacency matrices
For a graph with |V| vertices, an adjacency matrix is a |V|X|V| matrix of 0s and 1s, where the entry in row i and column j is 1 if and only if the edge (i,j) is in the graph. If you want to indicate an edge weight, put it in the row i column j entry, and reserve a special value (perhaps null) to indicate an absent edge.
With an adjacency matrix, we can find out whether an edge is present in constant time, by just looking up the corresponding entry in the matrix. For example, if the adjacency matrix is named graph, then we can query whether edge (i,j) is in the graph by looking at graph[i][j].
For an undirected graph, the adjacency matrix is symmetric: the row i, column j entry is 1 if and only if the row j, column i entry is 1. For a directed graph, the adjacency matrix need not be symmetric.
Adjacency lists
Representing a graph with adjacency lists combines adjacency matrices with edge lists. For each vertex i, store an array of the vertices adjacent to it. We typically have an array of |V| adjacency lists, one adjacency list per vertex.
Vertex numbers in an adjacency list are not required to appear in any particular order, though it is often convenient to list them in increasing order.
We can get to each vertex's adjacency list in constant time, because we just have to index into an array. To find out whether an edge (i,j) is present in the graph, we go to i's adjacency list in constant time and then look for j in i's adjacency list.
In an undirected graph, vertex j is in vertex i's adjacency list if and only if i is in j's adjacency list. If the graph is weighted, then each item in each adjacency list is either a two-item array or an object, giving the vertex number and the edge weight.
Export to file
How to export the data structure to a text file? Well, that's up to you based on how you would read the text file and import it into the data structure you decided to work with.
If I were to do it, I'd probably try to dump it in the most simple way for later to know how to read and parse it back to the data structure.
Adjacency list
store graphs in this format:
First line contains two integers: N (number of nodes) and E (number of edges).
ThenE lines follow each containing two integers U and V. each line represents an edge (edge goring from U to V)
This is how a cycle graph of four nodes would look like:
4 4
1 2
2 3
3 4
4 1
To represent graphs in python you can use a list of lists.
N, E = input() # input will take two comma separated integers
graph = [[] for x in range(N+1)] # initially no edge is inserted
for x in range(E): #to read E edges
u, v = input()
# inserting edge u->v
graph[u].append(v)

Graph updating algorithm

I have a (un-directed) graph represented using adjacency lists, e.g.
a: b, c, e
b: a, d
c: a, d
d: b, c
e: a
where each node of the graph is linked to a list of other node(s)
I want to update such a graph given some new list(s) for certain node(s), e.g.
a: b, c, d
where a is no longer connected to e, and is connected to a new node d
What would be an efficient (both time and space wise) algorithm for performing such updates to the graph?
Maybe I'm missing something, but wouldn't it be fastest to use a dictionary (or default dict) of node-labels (strings or numbers) to sets? In this case update could look something like this:
def update(graph, node, edges, undirected=True):
# graph: dict(str->set(str)), node: str, edges: set(str), undirected: bool
if undirected:
for e in graph[node]:
graph[e].remove(node)
for e in edges:
graph[e].add(node)
graph[node] = edges
Using sets and dicts, adding and removing the node to/from the edges-sets of the other nodes should be O(1), same as updating the edges-set for the node itself, so this should be only O(2n) for the two loops, with n being the average number of edges of a node.
Using an adjacency grid would make it O(n) to update, but would take n^2 space, regardless of how sparse the graph is. (Trivially done by updating each changed relationship by inverting the row and column.)
Using lists would put the time up to O(n^2) for updating, but for sparse graphs would not take a huge time penalty, and would save a lot of space.
A typical update is del edge a,e; add edge a,d, but your update looks like a new adjacency list for vertex a. So simply find the a adjacency list and replace it. That should be O(log n) time (assuming sorted array of adjacency lists, like in your description).

Categories