How to undo combinations of order 2?
Question:
I have a set of pairs:
inputs = {
('id1', 'id2'), ('id1', 'id3'), ('id1', 'id4'),
('id2', 'id3'), ('id2', 'id4'),
('id3', 'id4'), ('id3', 'id5'),
('id4', 'id5'),
('id5', 'id6'),
}
And I would like to reverse the combinations of order 2, like this:
recombinations = [
('id1', 'id2', 'id3', 'id4'),
('id3', 'id4', 'id5'),
('id5', 'id6'),
]
I managed to do it using brute-force:
ids = list(sorted( {i for i in itertools.chain(*inputs)} ))
excludes = set()
recombinations = {tuple(i) for i in map(sorted, inputs)}
for i in range(3, len(ids)+1):
for subset in itertools.combinations(ids, i):
for j in range(i-1, len(subset)):
combs = set(itertools.combinations(subset, j))
if all(tup in recombinations for tup in combs):
recombinations.add(subset)
excludes = excludes.union(combs)
for tup in excludes:
recombinations.remove(tup)
print(recombinations)
{('id1', 'id2', 'id3', 'id4'), ('id3', 'id4', 'id5'), ('id5', 'id6')}
My question is: is there a smarter way to do it or some optimizations that I could implement in the code?
Answers:
Using the networkx
library, this is quite simple, since it has a function that does exactly what you’re asking for: finding all maximal cliques in a graph.
Here:
import networkx as nx
G = nx.Graph()
pairs_of_connected_nodes = [
('id1', 'id2'), ('id1', 'id3'), ('id1', 'id4'),
('id2', 'id3'), ('id2', 'id4'),
('id3', 'id4'), ('id3', 'id5'),
('id4', 'id5'),
('id5', 'id6')
]
G.add_edges_from(pairs_of_connected_nodes)
maximal_cliques = list(nx.find_cliques(G))
for clique in maximal_cliques:
print(clique)
Output:
['id3', 'id4', 'id2', 'id1']
['id3', 'id4', 'id5']
['id6', 'id5']
Of course if your assignment is to implement the Bron-Kerbosch algorithm yourself, you’d have to code it up – but then asking on StackOverflow kind of defeats the purpose, unless you have a specific problem with your solution that you need help with?
If you’re just asking for a review of your code, ask on Code Review Stack Exchange, but expect to get told to use networkx
as well.
I have a set of pairs:
inputs = {
('id1', 'id2'), ('id1', 'id3'), ('id1', 'id4'),
('id2', 'id3'), ('id2', 'id4'),
('id3', 'id4'), ('id3', 'id5'),
('id4', 'id5'),
('id5', 'id6'),
}
And I would like to reverse the combinations of order 2, like this:
recombinations = [
('id1', 'id2', 'id3', 'id4'),
('id3', 'id4', 'id5'),
('id5', 'id6'),
]
I managed to do it using brute-force:
ids = list(sorted( {i for i in itertools.chain(*inputs)} ))
excludes = set()
recombinations = {tuple(i) for i in map(sorted, inputs)}
for i in range(3, len(ids)+1):
for subset in itertools.combinations(ids, i):
for j in range(i-1, len(subset)):
combs = set(itertools.combinations(subset, j))
if all(tup in recombinations for tup in combs):
recombinations.add(subset)
excludes = excludes.union(combs)
for tup in excludes:
recombinations.remove(tup)
print(recombinations)
{('id1', 'id2', 'id3', 'id4'), ('id3', 'id4', 'id5'), ('id5', 'id6')}
My question is: is there a smarter way to do it or some optimizations that I could implement in the code?
Using the networkx
library, this is quite simple, since it has a function that does exactly what you’re asking for: finding all maximal cliques in a graph.
Here:
import networkx as nx
G = nx.Graph()
pairs_of_connected_nodes = [
('id1', 'id2'), ('id1', 'id3'), ('id1', 'id4'),
('id2', 'id3'), ('id2', 'id4'),
('id3', 'id4'), ('id3', 'id5'),
('id4', 'id5'),
('id5', 'id6')
]
G.add_edges_from(pairs_of_connected_nodes)
maximal_cliques = list(nx.find_cliques(G))
for clique in maximal_cliques:
print(clique)
Output:
['id3', 'id4', 'id2', 'id1']
['id3', 'id4', 'id5']
['id6', 'id5']
Of course if your assignment is to implement the Bron-Kerbosch algorithm yourself, you’d have to code it up – but then asking on StackOverflow kind of defeats the purpose, unless you have a specific problem with your solution that you need help with?
If you’re just asking for a review of your code, ask on Code Review Stack Exchange, but expect to get told to use networkx
as well.