-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path62_morphogen_diffusion.py
More file actions
129 lines (110 loc) · 5.33 KB
/
62_morphogen_diffusion.py
File metadata and controls
129 lines (110 loc) · 5.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""
Example 62: Morphogen Diffusion — Spatially Varying Gradients
==============================================================
Demonstrates graph-based morphogen diffusion, implementing Paper §6.5.2 / §6.5.3.
Biological Analogy:
In embryonic development, morphogens (e.g., Bicoid in Drosophila) are
secreted from localized sources and diffuse through tissue. Cells near
the source see high concentration; cells far away see low concentration.
This gradient drives spatially patterned gene expression without any
central controller.
Since Operon agents lack physical coordinates, we use graph adjacency
from wiring topology as the spatial model.
Key points:
1. DiffusionField manages a graph of nodes and edges
2. MorphogenSource emits at a specific node
3. Concentrations diffuse along edges (emit → diffuse → decay → clamp)
4. get_local_gradient() bridges to the existing MorphogenGradient API
5. Tissue integration provides per-cell gradients
References:
- Article Section 6.5.2: Morphogen Gradients - Coordination Without Central Control
- Article Section 6.5.3: Tissue Architecture - The Agent Graph as Organism
"""
from operon_ai.coordination.diffusion import (
DiffusionField,
DiffusionParams,
MorphogenSource,
)
from operon_ai.coordination.morphogen import MorphogenType
def main():
try:
print("=" * 60)
print("Morphogen Diffusion — Spatially Varying Gradients")
print("=" * 60)
# ── 1. Linear chain with source ─────────────────────────────
print("\n--- 1. Linear Chain (A - B - C - D - E) ---")
field = DiffusionField()
nodes = ["A", "B", "C", "D", "E"]
for n in nodes:
field.add_node(n)
for i in range(len(nodes) - 1):
field.add_edge(nodes[i], nodes[i + 1])
field.add_source(MorphogenSource("A", MorphogenType.COMPLEXITY, 0.5))
print("Source at A, emission_rate=0.5")
print(f"Before diffusion: {field.snapshot()}")
# ── 2. Gradient formation over steps ────────────────────────
print("\n--- 2. Gradient Formation ---")
for step in [5, 10, 20, 50]:
f2 = DiffusionField()
for n in nodes:
f2.add_node(n)
for i in range(len(nodes) - 1):
f2.add_edge(nodes[i], nodes[i + 1])
f2.add_source(MorphogenSource("A", MorphogenType.COMPLEXITY, 0.5))
f2.run(step)
concs = [f2.get_concentration(n, MorphogenType.COMPLEXITY) for n in nodes]
bar = " ".join(f"{n}={c:.3f}" for n, c in zip(nodes, concs))
print(f" step {step:3d}: {bar}")
# ── 3. Star topology ───────────────────────────────────────
print("\n--- 3. Star Topology (center + 4 arms) ---")
star = DiffusionField()
star.add_node("center")
for arm in ["N", "S", "E", "W"]:
star.add_node(arm)
star.add_edge("center", arm)
star.add_source(MorphogenSource("center", MorphogenType.URGENCY, 0.3))
star.run(20)
print(f" center: {star.get_concentration('center', MorphogenType.URGENCY):.3f}")
for arm in ["N", "S", "E", "W"]:
print(f" {arm}: {star.get_concentration(arm, MorphogenType.URGENCY):.3f}")
# ── 4. Competing sources ───────────────────────────────────
print("\n--- 4. Competing Sources ---")
compete = DiffusionField(params=DiffusionParams(diffusion_rate=0.15, decay_rate=0.05))
for n in ["Left", "Mid", "Right"]:
compete.add_node(n)
compete.add_edge("Left", "Mid")
compete.add_edge("Mid", "Right")
compete.add_source(MorphogenSource("Left", MorphogenType.COMPLEXITY, 0.4))
compete.add_source(MorphogenSource("Right", MorphogenType.CONFIDENCE, 0.4))
compete.run(30)
snap = compete.snapshot()
print(f" Left: {snap.get('Left', {})}")
print(f" Mid: {snap.get('Mid', {})}")
print(f" Right: {snap.get('Right', {})}")
print(" (Complexity high at Left, Confidence high at Right, both present at Mid)")
# ── 5. Local gradients (MorphogenGradient bridge) ──────────
print("\n--- 5. Local Gradient API ---")
field.run(50)
for n in nodes:
g = field.get_local_gradient(n)
level = g.get_level(MorphogenType.COMPLEXITY)
val = g.get(MorphogenType.COMPLEXITY)
print(f" {n}: complexity={val:.3f} ({level})")
# ── 6. from_adjacency convenience ──────────────────────────
print("\n--- 6. from_adjacency ---")
ring = DiffusionField.from_adjacency({
"X": ["Y", "Z"],
"Y": ["X", "Z"],
"Z": ["X", "Y"],
})
ring.add_source(MorphogenSource("X", MorphogenType.ERROR_RATE, 0.3))
ring.run(10)
print(f" Ring: {ring.snapshot()}")
print("\n" + "=" * 60)
print("Morphogen diffusion demo complete.")
print("=" * 60)
except Exception as e:
print(f"ERROR: {e}")
raise
if __name__ == "__main__":
main()