Transformer fundamentals
 
Loading...
Searching...
No Matches
hra_testy.py
Go to the documentation of this file.
1import itertools
2import math
3import time
4from itertools import chain
5
6import matplotlib.pyplot as plt
7import networkx as nx
8from networkx.algorithms import isomorphism
9
10
11def generate_hras_accurate(n, verbose=True):
12 """
13 Generate all heritable regulatory architectures (HRAs) with n nodes.
14 This version emphasizes correctness while optimizing where possible.
15 """
16 start_time = time.time()
17 all_nodes = list(range(1, n + 1))
18 all_edges = list(itertools.permutations(all_nodes, r=2))
19
20 if verbose:
21 print(f"Finding weakly connected heritable topologies for n={n}...")
22
23 # Step 1: Find all weakly connected, heritable, non-isomorphic topologies
24 # "Heritable topology" means every node has at least one incoming edge
25 weakly_connected_heritable_non_iso_digraphs = []
26
27 # Optimization: Start with the minimum number of edges needed for heredity
28 # Each node needs at least one incoming edge, so minimum is n edges
29 min_edges = n
30
31 # For small n, we can afford to be thorough and check all possible edge configurations
32 # For n=4, there are 12 possible edges, so 2^12 = 4096 possible edge configurations
33 # which is still manageable with proper optimizations
34
35 # Generate edge sets more efficiently by starting with at least min_edges
36 valid_edge_sets = []
37 for k in range(min_edges, len(all_edges) + 1):
38 if verbose and k == min_edges:
39 print(f"Generating edge sets with at least {min_edges} edges...")
40 edge_combinations = itertools.combinations(all_edges, r=k)
41 valid_edge_sets.extend(edge_combinations)
42
43 if verbose:
44 print(f"Checking {len(valid_edge_sets)} potential edge configurations...")
45
46 # Process edge sets to find valid topologies
47 for idx, edge_set in enumerate(valid_edge_sets):
48 if verbose and idx % 10000 == 0 and idx > 0:
49 print(f"Processed {idx}/{len(valid_edge_sets)} edge sets...")
50
51 g = nx.DiGraph()
52 g.add_nodes_from(all_nodes)
53 g.add_edges_from(edge_set)
54
55 # Quick check: must be weakly connected and all nodes must have incoming edges
56 if not nx.is_weakly_connected(g):
57 continue
58
59 heritable = all(g.in_degree(i) > 0 for i in all_nodes)
60 if not heritable:
61 continue
62
63 # Isomorphism check (only if we've passed the quick checks)
64 found_isomorphic = False
65 for existing in weakly_connected_heritable_non_iso_digraphs:
66 if nx.is_isomorphic(g, existing):
67 found_isomorphic = True
68 break
69
70 if not found_isomorphic:
71 weakly_connected_heritable_non_iso_digraphs.append(g)
72
73 topology_time = time.time()
74 if verbose:
75 print(
76 f"Found {len(weakly_connected_heritable_non_iso_digraphs)} heritable topologies in {topology_time - start_time:.2f} seconds"
77 )
78
79 # Step 2: Generate all non-isomorphic regulatory architectures
80 non_iso_regulatory_architectures = []
81
82 if verbose:
83 print("Generating regulatory architectures...")
84
85 # Process each topology
86 for g_idx, g in enumerate(weakly_connected_heritable_non_iso_digraphs):
87 if verbose and g_idx % 10 == 0:
88 print(
89 f"Processing topology {g_idx+1}/{len(weakly_connected_heritable_non_iso_digraphs)}..."
90 )
91
92 edge_set = list(g.edges())
93 edge_count = len(edge_set)
94
95 # Generate all possible regulation patterns using product instead of combinations_with_replacement
96 # This matches the reference implementation logic better
97 for regulation_pattern in itertools.product(
98 ["gray", "black"], repeat=edge_count
99 ):
100 # Create regulated graph
101 regulated_g = nx.DiGraph()
102 regulated_g.add_nodes_from(all_nodes)
103
104 # Add edges with regulation attributes
105 regulation_to_edges = {}
106 for idx, (u, v) in enumerate(edge_set):
107 regulated_g.add_edge(u, v)
108 regulation_to_edges[(u, v)] = {"regulation": regulation_pattern[idx]}
109
110 nx.set_edge_attributes(regulated_g, regulation_to_edges)
111
112 # Check for isomorphism with existing regulatory architectures
113 found_isomorphic = False
114 for existing in non_iso_regulatory_architectures:
115 matcher = isomorphism.DiGraphMatcher(
116 regulated_g,
117 existing,
118 edge_match=lambda e1, e2: e1.get("regulation")
119 == e2.get("regulation"),
120 )
121 if matcher.is_isomorphic():
122 found_isomorphic = True
123 break
124
125 if not found_isomorphic:
126 non_iso_regulatory_architectures.append(regulated_g)
127
128 regulatory_time = time.time()
129 if verbose:
130 print(
131 f"Found {len(non_iso_regulatory_architectures)} non-isomorphic regulatory architectures in {regulatory_time - topology_time:.2f} seconds"
132 )
133
134 # Step 3: Filter for heritable regulatory architectures
135 # A regulatory architecture is heritable if every node has at least one incoming 'gray' edge
136 heritable_non_iso_regulatory_architectures = []
137
138 if verbose:
139 print("Filtering for heritable regulatory architectures...")
140
141 for regulated_g in non_iso_regulatory_architectures:
142 heritable = True
143 for node in all_nodes:
144 has_gray_incoming = False
145 for pred in regulated_g.predecessors(node):
146 if regulated_g[pred][node].get("regulation") == "gray":
147 has_gray_incoming = True
148 break
149
150 if not has_gray_incoming:
151 heritable = False
152 break
153
154 if heritable:
155 heritable_non_iso_regulatory_architectures.append(regulated_g)
156
157 end_time = time.time()
158 if verbose:
159 print(
160 f"Found {len(heritable_non_iso_regulatory_architectures)} heritable regulatory architectures in {end_time - start_time:.2f} seconds"
161 )
162 print(f"Total time: {end_time - start_time:.2f} seconds")
163
164 return {
165 "topologies": weakly_connected_heritable_non_iso_digraphs,
166 "regulatory": non_iso_regulatory_architectures,
167 "heritable": heritable_non_iso_regulatory_architectures,
168 }
169
170
171def plot_hras(hras, columns=5, max_plots=50):
172 """Plot the HRAs in a grid layout"""
173 if not hras:
174 print("No HRAs to plot")
175 return
176
177 # Limit the number of plots if needed
178 if len(hras) > max_plots:
179 print(f"Limiting display to first {max_plots} HRAs out of {len(hras)}")
180 hras = hras[:max_plots]
181
182 rows = (len(hras) + columns - 1) // columns
183 plt.figure(figsize=(columns * 3, rows * 3))
184
185 for i, g in enumerate(hras):
186 ax = plt.subplot(rows, columns, i + 1)
187 ax.axis("off")
188 pos = nx.circular_layout(g)
189
190 # Color nodes based on whether they regulate other nodes
191 node_color_map = []
192 for node in sorted(g.nodes()):
193 if g.out_degree(node) == 0:
194 node_color_map.append("blue")
195 else:
196 node_color_map.append("red")
197
198 # Get edge colors from the regulation attribute
199 edges = g.edges()
200 edge_color_map = [g[u][v]["regulation"] for u, v in edges]
201
202 nx.draw_networkx_nodes(g, pos, node_color=node_color_map, node_size=300, ax=ax)
203 nx.draw_networkx_edges(
204 g,
205 pos,
206 edge_color=edge_color_map,
207 width=2,
208 connectionstyle="arc3,rad=0.2",
209 ax=ax,
210 )
211 nx.draw_networkx_labels(g, pos, font_color="white", ax=ax)
212
213 plt.tight_layout()
214 plt.show()
215
216
218 """Count HRAs for different entity sizes to verify against expected results"""
219 results = []
220
221 for n in range(1, 5): # Test for n=1,2,3,4
222 start_time = time.time()
223 print(f"\nComputing for n={n}...")
224
225 data = generate_hras_accurate(n)
226
227 heritable_topologies = len(data["topologies"])
228 regulatory_archs = len(data["regulatory"])
229 heritable_archs = len(data["heritable"])
230
231 if heritable_archs > 0:
232 bits = round(math.log2(heritable_archs), 2)
233 else:
234 bits = "n/a"
235
236 results.append(
237 {
238 "n": n,
239 "heritable_topologies": heritable_topologies,
240 "regulatory_archs": regulatory_archs,
241 "heritable_archs": heritable_archs,
242 "bits": bits,
243 "time": time.time() - start_time,
244 }
245 )
246
247 print(f"\nResults for n={n}:")
248 print(f"Heritable Topologies: {heritable_topologies}")
249 print(f"Regulatory Architectures: {regulatory_archs}")
250 print(f"Heritable Regulatory Architectures: {heritable_archs}")
251 print(f"Bits: {bits}")
252 print(f"Time: {results[-1]['time']:.2f} seconds")
253
254 # Print summary table
255 print("\nSummary Table:")
256 print("Entities | Heritable Topologies | Regulatory Archs | Heritable Archs | Bits")
257 print("---------|---------------------|-----------------|----------------|------")
258 for r in results:
259 print(
260 f"{r['n']} | {r['heritable_topologies']} | {r['regulatory_archs']} | {r['heritable_archs']} | {r['bits']}"
261 )
262
263 return results
264
265
266# Example usage
267if __name__ == "__main__":
268 # Verify counts for smaller n values first
270
271 # Optional: For n=3, plot the heritable architectures
272 data = generate_hras_accurate(4, verbose=False)
273 plot_hras(data["heritable"])
generate_hras_accurate(n, verbose=True)
Generate all heritable regulatory architectures (HRAs) with n nodes.
Definition hra_testy.py:11
count_hras_by_size()
Count HRAs for different entity sizes to verify against expected results.
Definition hra_testy.py:217
plot_hras(hras, columns=5, max_plots=50)
Plot the HRAs in a grid layout.
Definition hra_testy.py:171