Критерий уникальности, который вы хотите использовать, называется изоморфизм графов . В NetworkX есть подмодуль: networkx.algorithms.isomorphism . Вы можете указать, как именно ваши узлы / ребра графов должны рассматриваться как «равные» с node_match/edge_match
параметрами. Вот пример:
import networkx as nx
FG1 = nx.Graph()
FG1.add_node(1, element='Cu')
FG1.add_node(2, element='Cu')
FG1.add_node(3, element='Mg')
FG1.add_weighted_edges_from([(1, 2, 1), (2, 3, 1), (3, 1, 2)])
FG2 = nx.Graph()
FG2.add_node(1, element='Cu')
FG2.add_node(2, element='Mg')
FG2.add_node(3, element='Cu')
FG2.add_weighted_edges_from([(1, 3, 1), (2, 3, 1), (1, 2, 2)])
nx.is_isomorphic(
FG1,
FG2,
node_match=lambda n1, n2: n1['element'] == n2['element'],
edge_match=lambda e1, e2: e1['weight'] == e2['weight']
)
True
Если вы переименуете какой-либо элемент или измените вес ребра, графики станут неизоморфными c (с этими параметрами). Именно так вы можете найти уникальные графы - множество неизоморфных c графов. Обратите внимание, что проблема изоморфизма графов очень сложна в вычислительном отношении, поэтому ее не следует использовать даже для графов среднего размера.
Но ваша задача имеет так много ограничений, что использование графов не является необходимым. Если у вас есть только 3 элемента в «молекуле», у вас будет только 3 типа комбинаций элементов:
1-1-1
1-1-2
1-2-3
Для каждого из них вы можете рассчитать и указать количество уникальных комбинаций:
1-1-1
: один - 1=1-1
1-1-2
: два - 1=1-2
и 1-1=2
1-2-3
: три - 1=2-3
, 1-2=3
и 1-2-3(=1)
Таким образом, вы можете просто умножить каждую комбинацию itertools на количество возможных комбинаций:
number_of_molecular_combinations = 0
for c in combinations:
number_of_molecular_combinations += len(set(c))
print(number_of_molecular_combinations)
18
This Метод будет работать намного быстрее, чем обработка графиков, но его можно использовать только в случае очень строгих ограничений, таких как у вас.