From 0ace1cec3c99d4c33ab0f05af60f8f336839e6a9 Mon Sep 17 00:00:00 2001 From: Morten Rohgalf Date: Fri, 26 Sep 2025 10:48:28 +0200 Subject: [PATCH] WIP: stochastic hill climber --- experiments/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 165 bytes experiments/phenotype_genotype_map/myg.json | 96 +++++ .../phenotype_genotype_map/network.dot | 22 ++ .../phenotype_genotype_map/network.png | Bin 0 -> 69406 bytes .../phenotype_genotype_map/network_new.png | Bin 0 -> 24041 bytes .../phenotype_genotype_map/visualizer.py | 72 ++++ .../stochastic_hillclimber/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 188 bytes experiments/stochastic_hillclimber/actors.zip | Bin 0 -> 61865 bytes .../stochastic_hillclimber/actors/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 195 bytes .../actors/__pycache__/actor.cpython-312.pyc | Bin 0 -> 1028 bytes .../__pycache__/actuator.cpython-312.pyc | Bin 0 -> 2941 bytes .../actors/__pycache__/cortex.cpython-312.pyc | Bin 0 -> 5207 bytes .../__pycache__/exoself.cpython-312.pyc | Bin 0 -> 16058 bytes .../__pycache__/genotype.cpython-312.pyc | Bin 0 -> 8474 bytes .../__pycache__/morphology.cpython-312.pyc | Bin 0 -> 3646 bytes .../actors/__pycache__/neuron.cpython-312.pyc | Bin 0 -> 6806 bytes .../actors/__pycache__/scape.cpython-312.pyc | Bin 0 -> 3070 bytes .../actors/__pycache__/sensor.cpython-312.pyc | Bin 0 -> 2662 bytes .../__pycache__/trainer.cpython-312.pyc | Bin 0 -> 5808 bytes .../stochastic_hillclimber/actors/actor.py | 13 + .../stochastic_hillclimber/actors/actuator.py | 55 +++ .../stochastic_hillclimber/actors/best.json | 96 +++++ .../stochastic_hillclimber/actors/cortex.py | 119 ++++++ .../stochastic_hillclimber/actors/exoself.py | 346 ++++++++++++++++++ .../actors/experimental.json | 96 +++++ .../stochastic_hillclimber/actors/genotype.py | 266 ++++++++++++++ .../actors/morphology.py | 104 ++++++ .../stochastic_hillclimber/actors/mtest.py | 39 ++ .../stochastic_hillclimber/actors/neuron.py | 105 ++++++ .../stochastic_hillclimber/actors/scape.py | 58 +++ .../stochastic_hillclimber/actors/sensor.py | 45 +++ .../stochastic_hillclimber/actors/test.json | 179 +++++++++ .../stochastic_hillclimber/actors/trainer.py | 151 ++++++++ experiments/stochastic_hillclimber/run.py | 0 37 files changed, 1862 insertions(+) create mode 100644 experiments/__init__.py create mode 100644 experiments/__pycache__/__init__.cpython-312.pyc create mode 100644 experiments/phenotype_genotype_map/myg.json create mode 100644 experiments/phenotype_genotype_map/network.dot create mode 100644 experiments/phenotype_genotype_map/network.png create mode 100644 experiments/phenotype_genotype_map/network_new.png create mode 100644 experiments/phenotype_genotype_map/visualizer.py create mode 100644 experiments/stochastic_hillclimber/__init__.py create mode 100644 experiments/stochastic_hillclimber/__pycache__/__init__.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors.zip create mode 100644 experiments/stochastic_hillclimber/actors/__init__.py create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/__init__.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/actor.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/actuator.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/cortex.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/exoself.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/genotype.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/morphology.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/neuron.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/scape.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/sensor.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/__pycache__/trainer.cpython-312.pyc create mode 100644 experiments/stochastic_hillclimber/actors/actor.py create mode 100644 experiments/stochastic_hillclimber/actors/actuator.py create mode 100644 experiments/stochastic_hillclimber/actors/best.json create mode 100644 experiments/stochastic_hillclimber/actors/cortex.py create mode 100644 experiments/stochastic_hillclimber/actors/exoself.py create mode 100644 experiments/stochastic_hillclimber/actors/experimental.json create mode 100644 experiments/stochastic_hillclimber/actors/genotype.py create mode 100644 experiments/stochastic_hillclimber/actors/morphology.py create mode 100644 experiments/stochastic_hillclimber/actors/mtest.py create mode 100644 experiments/stochastic_hillclimber/actors/neuron.py create mode 100644 experiments/stochastic_hillclimber/actors/scape.py create mode 100644 experiments/stochastic_hillclimber/actors/sensor.py create mode 100644 experiments/stochastic_hillclimber/actors/test.json create mode 100644 experiments/stochastic_hillclimber/actors/trainer.py create mode 100644 experiments/stochastic_hillclimber/run.py diff --git a/experiments/__init__.py b/experiments/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/experiments/__pycache__/__init__.cpython-312.pyc b/experiments/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0b42b2781fe8cabc4abc463f2590b3308d0ab8e GIT binary patch literal 165 zcmX@j%ge<81iQGeW`O9&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<)R;2oLW?@pPOG) zlA2ePpOK!Jlcrx#l%JKFTvDu`ms(nspIVlmQ(BUlpQoQ%QIJ}cnVXsil!}kf%*!l^ lkJl@x{Ka9Do1apelWJGQ3N(}vh>JmtkIamWj77{q768WuD;EF& literal 0 HcmV?d00001 diff --git a/experiments/phenotype_genotype_map/myg.json b/experiments/phenotype_genotype_map/myg.json new file mode 100644 index 0000000..354a447 --- /dev/null +++ b/experiments/phenotype_genotype_map/myg.json @@ -0,0 +1,96 @@ +{ + "cortex": { + "id": 0.8543980322495442, + "sensor_ids": [ + 5.685640276474605e-10 + ], + "actuator_ids": [ + 5.685640276474598e-10 + ], + "neuron_ids": [ + 0.15322756084303968, + 0.7120745036860967, + 0.024186022052107514 + ] + }, + "sensor": { + "id": 5.685640276474605e-10, + "name": "xor_GetInput", + "vector_length": 2, + "cx_id": 0.8543980322495442, + "fanout_ids": [ + 0.15322756084303968, + 0.7120745036860967 + ] + }, + "actuator": { + "id": 5.685640276474598e-10, + "name": "xor_SendOutput", + "vector_length": 1, + "cx_id": 0.8543980322495442, + "fanin_ids": [ + 0.024186022052107514 + ] + }, + "neurons": [ + { + "id": 0.15322756084303968, + "layer_index": 0, + "cx_id": 0.8543980322495442, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685640276474605e-10, + "weights": [ + -1.463374592873151, + -0.941866321100616 + ] + } + ], + "output_ids": [ + 0.32112185541392557 + ] + }, + { + "id": 0.7120745036860967, + "layer_index": 0, + "cx_id": 0.8543980322495442, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685640276474605e-10, + "weights": [ + 1.8732878918890417, + 1.4545727537289697 + ] + } + ], + "output_ids": [ + 0.32112185541392557 + ] + }, + { + "id": 0.024186022052107514, + "layer_index": 1, + "cx_id": 0.8543980322495442, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.15322756084303968, + "weights": [ + -1.3198353764897197 + ] + }, + { + "input_id": 0.7120745036860967, + "weights": [ + -1.8234720470310797 + ] + } + ], + "output_ids": [ + 5.685640276474598e-10 + ] + } + ] +} \ No newline at end of file diff --git a/experiments/phenotype_genotype_map/network.dot b/experiments/phenotype_genotype_map/network.dot new file mode 100644 index 0000000..90862df --- /dev/null +++ b/experiments/phenotype_genotype_map/network.dot @@ -0,0 +1,22 @@ +digraph G { + rankdir=TB; + node [fontsize=10]; + subgraph cluster_sensors { label="Sensors"; style=dashed; + "S0.000000" [label="xor_GetInput", shape=box]; + } + subgraph cluster_L0 { label="Layer 0"; style=rounded; + "N0.153228" [label="N0", shape=circle]; + "N0.712075" [label="N0", shape=circle]; + } + subgraph cluster_L1 { label="Layer 1"; style=rounded; + "N0.024186" [label="N1", shape=circle]; + } + subgraph cluster_actuators { label="Actuators"; style=dashed; + "A0.000000" [label="xor_SendOutput", shape=diamond]; + } + "S0.000000" -> "N0.153228" [label="w×2"]; + "S0.000000" -> "N0.712075" [label="w×2"]; + "N0.153228" -> "N0.024186" [label="w×1"]; + "N0.712075" -> "N0.024186" [label="w×1"]; + "N0.024186" -> "A0.000000" [label="out"]; +} \ No newline at end of file diff --git a/experiments/phenotype_genotype_map/network.png b/experiments/phenotype_genotype_map/network.png new file mode 100644 index 0000000000000000000000000000000000000000..06da007512532efa67e79ed0d413659dbca8aaa3 GIT binary patch literal 69406 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 literal 0 HcmV?d00001 diff --git a/experiments/phenotype_genotype_map/network_new.png b/experiments/phenotype_genotype_map/network_new.png new file mode 100644 index 0000000000000000000000000000000000000000..20dc2170a1376f3b4c1915c131b10b165afc30ee GIT binary patch literal 24041 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 literal 0 HcmV?d00001 diff --git a/experiments/phenotype_genotype_map/visualizer.py b/experiments/phenotype_genotype_map/visualizer.py new file mode 100644 index 0000000..a7cbccc --- /dev/null +++ b/experiments/phenotype_genotype_map/visualizer.py @@ -0,0 +1,72 @@ +import json + + +def load_geno(p="myg.json"): + with open(p) as f: + return json.load(f) + + +def to_dot(geno: dict) -> str: + sensors = [] + if "sensors" in geno: + sensors = geno["sensors"] + elif "sensor" in geno: + sensors = [geno["sensor"]] + + actuators = [] + if "actuators" in geno: + actuators = geno["actuators"] + elif "actuator" in geno: + actuators = [geno["actuator"]] + + neurons = geno["neurons"] + + lines = [] + lines.append('digraph G {') + lines.append(' rankdir=TB;') # top-to-bottom + lines.append(' node [fontsize=10];') + + lines.append(' subgraph cluster_sensors { label="Sensors"; style=dashed;') + for s in sensors: + lines.append(f' "S{float(s["id"]):.6f}" [label="{s.get("name", "sensor")}", shape=box];') + lines.append(' }') + + by_layer = {} + for n in neurons: + by_layer.setdefault(n["layer_index"], []).append(n) + + for li in sorted(by_layer.keys()): + lines.append(f' subgraph cluster_L{li} {{ label="Layer {li}"; style=rounded;') + for n in by_layer[li]: + lines.append(f' "N{float(n["id"]):.6f}" [label="N{li}", shape=circle];') + lines.append(' }') + + lines.append(' subgraph cluster_actuators { label="Actuators"; style=dashed;') + for a in actuators: + lines.append(f' "A{float(a["id"]):.6f}" [label="{a.get("name", "act")}", shape=diamond];') + lines.append(' }') + + for n in neurons: + to_id = f'N{float(n["id"]):.6f}' + for iw in n["input_weights"]: + src = iw["input_id"] + wcount = len(iw["weights"]) + is_sensor = any(abs(src - s["id"]) < 1e-9 for s in sensors) + from_id = f'S{float(src):.6f}' if is_sensor else f'N{float(src):.6f}' + lines.append(f' "{from_id}" -> "{to_id}" [label="w×{wcount}"];') + + for a in actuators: + to_id = f'A{float(a["id"]):.6f}' + for src in a.get("fanin_ids", []): + lines.append(f' "N{float(src):.6f}" -> "{to_id}" [label="out"];') + + lines.append('}') + return "\n".join(lines) + + +if __name__ == "__main__": + geno = load_geno("myg.json") + dot = to_dot(geno) + with open("network.dot", "w") as f: + f.write(dot) + print("Wrote network.dot") diff --git a/experiments/stochastic_hillclimber/__init__.py b/experiments/stochastic_hillclimber/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/experiments/stochastic_hillclimber/__pycache__/__init__.cpython-312.pyc b/experiments/stochastic_hillclimber/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b6d234b28cb7f489d81806d40773f056deda44a GIT binary patch literal 188 zcmZ8au?+$-3`}^C5a9xK(W^9g literal 0 HcmV?d00001 diff --git a/experiments/stochastic_hillclimber/actors.zip b/experiments/stochastic_hillclimber/actors.zip new file mode 100644 index 0000000000000000000000000000000000000000..e5dffedf7246385bc0cc236df4222a662948cc3c GIT binary patch literal 61865 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 literal 0 HcmV?d00001 diff --git a/experiments/stochastic_hillclimber/actors/__pycache__/actuator.cpython-312.pyc b/experiments/stochastic_hillclimber/actors/__pycache__/actuator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..764b4eead0d35d08f07ebefdfa916f20a583ede9 GIT binary patch literal 2941 zcmb_eZ%iD=6`$GN`wMqqIN2K@Cmpih>h61PoRxJB=N;5=ymN-|iiI-P^s+ z?%6=^A}g_4A`uCsws4K2!~Ie$tF`kfq#s&;u+mEXau_UDD?U)AmFjP_G?nX5eY3}M zE;!#h($0Ht-kUdX-u~vz{5cTtBWQoQ@Oa{L4?ApxI5&eP@wn>>igT719OVS+3j*D19B|a%&hMf7IbJ}9Ii_5?y@kW#u=SLapuyr&)MY3c&+8qb6JU4UY?g#+2DDL6=czJCnotUP?w+z z8Oib`1yxpgS=24JG?|qWhUFzvLXxjbV5295tYmoveM(Kpn&o;sC*>ro#vTT**R;vF z*Wz?ZNfIAKLMR$6jyfi_l&!6}HAo#D^6`8^5p7fyr0bfJGh|Keqkf5;kyKFWhL)HRbVE+?6SATt6ghKE zB7Fh{j!udF+k3N9gf2LJ$jMQ!lNdUze-FB+H_@gy@S$hb8(th(y0Ub>9O+*7_Lz;$ zGu*7#Y(4^{#%ziJ@tcu$AVIU4k{UA{1rjiuDDiI|ZZEx7eC^|NGu&fucn3VA#4dU$ zk0=H{fNy6OaPu960mD8(Lz?RLwe%jcstV`-e*lN+$DscOv%vnuy@$`L&ph`k2u2l;FSK&b0QjIu+t+s2`>wHvN|AMD zV3a}yz<8SCVqY6UKZrqmp1eCvA+oQ1O}rku&#L#?c8+GSe&1veMUKWrLeE9z%Deyf zM2qfs;XD_-1)ut}ukqrsz1#$C!@)I(@tk*WHL4d|r<)FX5Ph@)B=_>Q|KH;O4?_HT ze+40;-`-Elb8*+?{dae(8q_$ySW7buG+-mjSMaLt**CB8$M{8 z_vU>`&dJun9X}Uay<-KDy%3q{!w3C4=L93w4d>yIy<lHI{mJ zSH>(ik@TEmOt)5Nr8J{r7Xw{ZQ*~)D_JkIiCv+2g>jV1jO>wl0Pj^=5!>Zr_24fjX z*M*cs7f#RuJlSjc42fi9RWPJ@&~n+u-eOadL4q_vtO7+kKsi^I$WYwvdJk6!6mOBx z0#GUUa5;cX?*;pYuv`g65=gv;&>PNTGkVHm4IyP=9&%2!4BSK(dtFLc?n)XhHVGr1 zq->}VqUDU8a1od=1orY}Qk{!WYhRO9@u6(@R$$wRCTWkCtOE-|xI1F1HS@htHTN zPpyW#7d^KlX5?roT8x%Y^goL9uZ;ZR&ELIAjax_7!{^P`_ENf-E@?$=d2*%sL8#n2 zy4E_j5gsdt$3SVuPu`2(iQa3y)4CQP*ytEo9D(qbhKe_qyB@W@vKc#G?i~FSw;sD_ zersUmrBA=VB0hNe^VD)=$z#TjZ`YuLf9o}qmlUy8fwJBU6^;2q@W`HUv!6w24~ z{Eu>iQqkBC1ag`}D6soXNl1#q^KndQt<&k*dfmntp|3i-qgSR*Pr}n%=qtwO>iKu` zF;@$r_0HDEIYMtGcyQ4N38DA7J$?sOY$#%%d0(wWbe5a}kuIataexTMU!vgOP|LsE P-^495xvvlqd*XiqWLlyu literal 0 HcmV?d00001 diff --git a/experiments/stochastic_hillclimber/actors/__pycache__/cortex.cpython-312.pyc b/experiments/stochastic_hillclimber/actors/__pycache__/cortex.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd6e28dec9ebae02ea318547ea097fbd5abf2a16 GIT binary patch literal 5207 zcmb^#ZEPdOb;e%X>)3HN_QrPX#OF(b6Xz1=3%E8#_o3WfRT`x#1*t@!t?_Ph&N+72 z-Q0)IX%U=C+8%B0BuGwxE)ujHI#mT)weSnUkBYA!*~HZD>MErIspVg|(Dv?r_06o; z4vAZ}5+m)~H}l@SnR#FPWR*Y>NQCjWEPX0nGruyB$N1h7no-zn-c3ZH-67rl&szp?e-Up0g}l ze{8dX#Eb0=I)@ITi;iDg&)~R)#4AIr9=FKEA&E7!B6R$ugB681S~M!da!79!PNh?) zgo<eq>sN7MV6aemfJ41-9*^gwRp7b^)1IP#a3E3yqzU?r{?bb+zN!U zyYr4h{Qt?WLHsM6u)o3%;ysEX2i-ma07AT~G)NspMb%ISa-|(ZW>A{SfUv6aL0DNP zzO)1(jli>gHvm)jk8%|)SA_0-J%^Vu=+jH|Np*>dF0IKlXiv8!26dd=sk}SR`=+HV zc&mIUpD-0COAvm-R8AJM(iwq9SmM4+E|ttEhZ0qOqI-o0KvlXPJ$!9wwfU8nU$$t` z!?zXUG*9}2IBu0mK9Wi5kYV5GRZNYj5M@;i$P0B=%!mKWc0w>&X$1g5(H?~bUt|8@ zdEHZt9^Pm_yvTgahU7M&?olPR*3W?gUlEdQ0W%s+i#7X^Bw4izSdv8Hu4dX1Bej}N zXR4{R#%%I|#A=GBiMA>etj(-yfP)Ea`RbL zlI0dcB{q&-N%_rW4moAaW1rn%HPpGj#}`NHkOZ?A4e|`rgFi zBr~ddug#dL+N?JApQMn4CSu}k3zmXKw44H6%l8-XBj6zm)&)j&nKBB@j;OA#3OgWQ zpj}P*%FlZ74D8NIcDID(*Xyqel$TZFU9^cz0bj59IVnFLfv8=uE!Y}o3Uf7(EHC3^FaX;PM2i9_d- z^uMdA#Gtgn`d^+~vnP~lGu0BvxQU64z+1~{{OtPWVx7t zXltUmpcnT0m1ZrF{wPT2sPy9?y?58fp$nsX2T|Uj^z9`PN~J(+C^XcyMziTnd$ns6 zXs{+9Dyf5OBvq;{Xpto zS(;8O@co0jzjA$$BXGQYXzV)=Jb3*3qtWS{8YSgpbQUfQ$!Tdcn&@GH=Imnp!Ufmr$_SvQ=EAbp)x^M&?L~>D4NR6&SfN35)+@1qw2hLI+=lM z4O|4^OI@Lz&>LilUQv>&q&s2vv*|3LaV(PpPxn5SOr4sa6Q<+M#QeIWqBq@HRh#aR zGRZkb66F|hC?o>u4axvU#cq}7v-yTfB?9}^>}UWzS_ZP^j$ zTl4p>H}#f7?Ux)&c@9Me6zx41DQ{+0zf$;MA%je5{u*45&{6LW(Du*JaP@fj+ z+Xy8}d}57Hl)2z$lXq$AXA7(RE8&;IH@KEH|L|*LMeb{xi6MpTM4YjKP7~o zA{PgaC28e>A{Qmt)Jh7LBG}AocaiHQSZ4KGMJ@rDF#-13+*0DA>s<8Z$vEm(H(#_wtW!bi_&> zBU;DEM#nvGGHco|aa$Dz? z({@j28`<`S|AlO=;VlY0sJm~4dC|4SqVAp*<^>m+tP~v5fOHs zcr7^mS3}>K^`?$ZjxTWsK*dF_AL`1Izen@;Z1{UiT<;p!`)7mk)OyqY%~0fO-<7^= z{BI(!MzqkuH@n{Mdkd_10xoyWLrX`?q43q%mDp-zBQ#jz2Q_|h%L;@|&cE5ruLb+o zoBKA2{FvsCmHY=Z|AA{`8~(u(H@L<^#93+^A*f)>Z>*9=f9}fj>VvI3C7t;Bl7uZ3kfQwBT_U^N#a9-y$5z_^qAj>#rxCHNiFAPBQLaUTAh2)bJk9-mKU z3<~`TL353f4QT2agX6$0+xRV#k}?@VfUHIDU?krip+PN^x|{-1_$nkH-@1Ulur%6& zHzO8X*G(4Nj^LYiyDj`r?g4BYqW1(kA-t1iSZ}M^%oTQ!u~kMLyHgn1CckK`frtmJrMu^ literal 0 HcmV?d00001 diff --git a/experiments/stochastic_hillclimber/actors/__pycache__/exoself.cpython-312.pyc b/experiments/stochastic_hillclimber/actors/__pycache__/exoself.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfb5e11a74e2d83fc73bad3c43b9f12ac849d978 GIT binary patch literal 16058 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 literal 0 HcmV?d00001 diff --git a/experiments/stochastic_hillclimber/actors/__pycache__/trainer.cpython-312.pyc b/experiments/stochastic_hillclimber/actors/__pycache__/trainer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd284cf16e953dfb1573dd772f652a649189c105 GIT binary patch literal 5808 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 literal 0 HcmV?d00001 diff --git a/experiments/stochastic_hillclimber/actors/actor.py b/experiments/stochastic_hillclimber/actors/actor.py new file mode 100644 index 0000000..f3fd26f --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/actor.py @@ -0,0 +1,13 @@ +import asyncio + + +class Actor: + def __init__(self, name: str): + self.name = name + self.inbox = asyncio.Queue() + + async def send(self, msg): + await self.inbox.put(msg) + + async def run(self): + raise NotImplementedError diff --git a/experiments/stochastic_hillclimber/actors/actuator.py b/experiments/stochastic_hillclimber/actors/actuator.py new file mode 100644 index 0000000..604eab3 --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/actuator.py @@ -0,0 +1,55 @@ +# actors/actuator.py +import asyncio + +from actor import Actor + + +class Actuator(Actor): + def __init__(self, aid, cx_pid, name, fanin_ids, expect_count, scape=None): + super().__init__(f"Actuator-{aid}") + self.aid = aid + self.cx_pid = cx_pid + self.aname = name + self.fanin_ids = fanin_ids + self.expect = expect_count + self.received = {} + self.scape = scape + self.scape_inbox = asyncio.Queue() + + async def run(self): + + while True: + msg = await self.inbox.get() + tag = msg[0] + + if tag == "forward": + _, from_id, vec = msg + self.received[from_id] = vec + + if len(self.received) == self.expect: + print("ACTUATOR: collected all signals...") + output = [] + for fid in self.fanin_ids: + output.extend(self.received[fid]) + + if self.aname == "pts": + print(f"Actuator output: {output}") + fitness, halt_flag = 1.0, 0 + elif self.aname == "xor_SendOutput" and self.scape: + print("ACTUATOR: sending action to scape...") + await self.scape.send(("action", output, self)) + while True: + resp = await self.inbox.get() + if resp[0] == "result": + print("ACTUATOR: got scape response: ", resp) + fitness, halt_flag = resp[1], resp[2] + break + else: + fitness, halt_flag = 0.0, 0 + + await self.cx_pid.send(("sync", self.aid, fitness, halt_flag)) + print("ACTUATOR: sent sync message to cortex.") + self.received.clear() + + elif tag == "terminate": + return diff --git a/experiments/stochastic_hillclimber/actors/best.json b/experiments/stochastic_hillclimber/actors/best.json new file mode 100644 index 0000000..fd0196d --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/best.json @@ -0,0 +1,96 @@ +{ + "cortex": { + "id": 0.5107239887106383, + "sensor_ids": [ + 5.685637947817566e-10 + ], + "actuator_ids": [ + 5.685637947817563e-10 + ], + "neuron_ids": [ + 0.3776999353275148, + 0.7030052650887313, + 0.9936497204289092 + ] + }, + "sensor": { + "id": 5.685637947817566e-10, + "name": "xor_GetInput", + "vector_length": 2, + "cx_id": 0.5107239887106383, + "fanout_ids": [ + 0.3776999353275148, + 0.7030052650887313 + ] + }, + "actuator": { + "id": 5.685637947817563e-10, + "name": "xor_SendOutput", + "vector_length": 1, + "cx_id": 0.5107239887106383, + "fanin_ids": [ + 0.9936497204289092 + ] + }, + "neurons": [ + { + "id": 0.3776999353275148, + "layer_index": 0, + "cx_id": 0.5107239887106383, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685637947817566e-10, + "weights": [ + -1.7328567115118854, + 0.31546591460152307 + ] + } + ], + "output_ids": [ + 0.24149710385676537 + ] + }, + { + "id": 0.7030052650887313, + "layer_index": 0, + "cx_id": 0.5107239887106383, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685637947817566e-10, + "weights": [ + 1.507492385500833, + -1.5181033637128052 + ] + } + ], + "output_ids": [ + 0.24149710385676537 + ] + }, + { + "id": 0.9936497204289092, + "layer_index": 1, + "cx_id": 0.5107239887106383, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.3776999353275148, + "weights": [ + 0.9998252528454215 + ] + }, + { + "input_id": 0.7030052650887313, + "weights": [ + -1.7243886895741118 + ] + } + ], + "output_ids": [ + 5.685637947817563e-10 + ] + } + ] +} \ No newline at end of file diff --git a/experiments/stochastic_hillclimber/actors/cortex.py b/experiments/stochastic_hillclimber/actors/cortex.py new file mode 100644 index 0000000..9197530 --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/cortex.py @@ -0,0 +1,119 @@ +# actors/cortex.py +import time +from actor import Actor + + +class Cortex(Actor): + def __init__(self, cid, exoself_pid, sensor_pids, neuron_pids, actuator_pids): + super().__init__(f"Cortex-{cid}") + self.cid = cid + self.sensors = sensor_pids + self.neurons = neuron_pids + self.actuators = actuator_pids + self.exoself_pid = exoself_pid + + self.awaiting_sync = set() # AIDs, von denen wir im aktuellen Schritt noch Sync erwarten + self.fitness_acc = 0.0 # akkumulierte Fitness über die Episode + self.ef_acc = 0 # akkumulierte EndFlags im aktuellen Schritt/Episode + self.cycle_acc = 0 # Anzahl abgeschlossener Sense-Think-Act Zyklen + self.active = False # aktiv/inaktiv (wartet auf reactivate) + self._t0 = None # Startzeit der Episode + + async def _kick_sensors(self): + for s in self.sensors: + await s.send(("sync",)) + + def _reset_for_new_cycle(self): + self.awaiting_sync = set(a.aid for a in self.actuators) + + def _reset_for_new_episode(self): + self.fitness_acc = 0.0 + self.ef_acc = 0 + self.cycle_acc = 0 + self._reset_for_new_cycle() + self._t0 = time.perf_counter() + self.active = True + + async def run(self): + # Initialisierung: falls Actuatoren schon gesetzt sind, Episode starten + if self.actuators: + self._reset_for_new_episode() + await self._kick_sensors() + + while True: + msg = await self.inbox.get() + tag = msg[0] + + # Optional: Exoself kann AIDs registrieren, bevor wir starten + if tag == "register_actuators": + _, aids = msg + # Map aids auf echte Actuatoren falls nötig; hier übernehmen wir sie direkt + self.awaiting_sync = set(aids) + if not self.active: + self._reset_for_new_episode() + await self._kick_sensors() + continue + + if tag == "sync" and self.active: + print("CORTEX: got sync message: ", msg) + # Aktuator meldet Schrittabschluss + _t, aid, fitness, halt_flag = msg + + print("----------------") + print("_t:", _t) + print("aid:", aid) + print("fitness:", fitness) + print("halt_flag:", halt_flag) + print("----------------") + + # akkumulieren + self.fitness_acc += float(fitness) + self.ef_acc += int(halt_flag) + + # diesen Aktuator als "eingetroffen" markieren + if aid in self.awaiting_sync: + self.awaiting_sync.remove(aid) + + print("CORTEX: awaiting sync: ", self.awaiting_sync) + + # Wenn alle Aktuatoren gemeldet haben, ist ein Zyklus fertig + if not self.awaiting_sync: + print("CORTEX: cycle completed.") + self.cycle_acc += 1 + + # Episodenende, wenn irgendein Aktuator EndFlag setzt + if self.ef_acc > 0: + elapsed = time.perf_counter() - self._t0 + # An Exoself berichten + await self.exoself_pid.send(( + "evaluation_completed", + self.fitness_acc, + self.cycle_acc, + elapsed + )) + # inaktiv werden – warten auf reactivate + self.active = False + # Flags für nächste Episode werden erst bei reactivate gesetzt + else: + # Nächsten Zyklus starten + self.ef_acc = 0 + self._reset_for_new_cycle() + await self._kick_sensors() + + continue + + if tag == "reactivate": + # neue Episode starten + self._reset_for_new_episode() + await self._kick_sensors() + continue + + if tag == "terminate": + # geordnet alle Kinder beenden + for a in (self.sensors + self.actuators + self.neurons): + await a.send(("terminate",)) + return + + elif tag == "backup_from_neuron": + # vom Neuron an Cortex -> an Exoself weiterreichen + await self.exoself_pid.send(msg) diff --git a/experiments/stochastic_hillclimber/actors/exoself.py b/experiments/stochastic_hillclimber/actors/exoself.py new file mode 100644 index 0000000..fd97b98 --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/exoself.py @@ -0,0 +1,346 @@ +# exoself.py +import asyncio +import json +import math +import random +from collections import defaultdict +from typing import Any, Dict, List, Tuple, Optional + +from actor import Actor +from cortex import Cortex +from sensor import Sensor +from neuron import Neuron +from actuator import Actuator +from scape import XorScape + + +class Exoself(Actor): + """ + Exoself übersetzt den Genotyp (JSON) in einen laufenden Phenotyp (Actors) und + steuert das simple Neuroevolution-Training (Backup/Restore/Perturb + Reactivate). + """ + def __init__(self, genotype: Dict[str, Any], file_name: Optional[str] = None): + super().__init__("Exoself") + self.g = genotype + self.file_name = file_name + + self.cx_actor: Optional[Cortex] = None + self.sensor_actors: List[Sensor] = [] + self.neuron_actors: List[Neuron] = [] + self.actuator_actors: List[Actuator] = [] + + self.tasks: List[asyncio.Task] = [] + + # Training-Stats + self.highest_fitness = float("-inf") + self.eval_acc = 0 + self.cycle_acc = 0 + self.time_acc = 0.0 + self.attempt = 0 + self.MAX_ATTEMPTS = 50 + self.actuator_scape = None + + # zuletzt perturbierte Neuronen (für Restore) + self._perturbed: List[Neuron] = [] + + # ---------- Convenience ---------- + @staticmethod + def from_file(path: str) -> "Exoself": + with open(path, "r") as f: + g = json.load(f) + return Exoself(g, file_name=path) + + # ---------- Public API ---------- + async def run(self): + # 1) Netzwerk bauen + self._build_pid_map_and_spawn() + + # 2) Cortex verlinken + starten + self._link_cortex() + + # 3) Actors starten (Sensoren/Neuronen/Aktuatoren) + for a in self.sensor_actors + self.neuron_actors + self.actuator_actors + [self.actuator_scape]: + self.tasks.append(asyncio.create_task(a.run())) + + # 4) Hauptloop: auf Cortex-Events hören + while True: + msg = await self.inbox.get() + tag = msg[0] + + if tag == "evaluation_completed": + _, fitness, cycles, elapsed = msg + await self._on_evaluation_completed(fitness, cycles, elapsed) + + elif tag == "terminate": + await self._terminate_all() + return + + # in exoself.py, innerhalb der Klasse Exoself + + async def run_evaluation(self): + """ + Eine einzelne Episode/Evaluation: + - baut & verlinkt das Netz + - startet alle Actors + - wartet auf 'evaluation_completed' vom Cortex + - beendet alles und liefert (fitness, evals, cycles, elapsed) + """ + # 1) Netzwerk bauen & Cortex verlinken + print("build network and link...") + self._build_pid_map_and_spawn() + print("link cortex...") + self._link_cortex() + + # 2) Sensor/Neuron/Aktuator-Tasks starten (Cortex startete _link_cortex bereits) + for a in self.sensor_actors + self.neuron_actors + self.actuator_actors: + self.tasks.append(asyncio.create_task(a.run())) + + if self.actuator_scape: + self.tasks.append(asyncio.create_task(self.actuator_scape.run())) + + print("network actors are running...") + + # 3) Auf Abschluss warten + while True: + msg = await self.inbox.get() + print("message in exsoself: ", msg) + tag = msg[0] + if tag == "evaluation_completed": + _, fitness, cycles, elapsed = msg + # 4) Sauber terminieren + await self._terminate_all() + # Evals = 1 (eine Episode) + return float(fitness), 1, int(cycles), float(elapsed) + elif tag == "terminate": + await self._terminate_all() + # Falls vorzeitig terminiert wurde + return float("-inf"), 0, 0, 0.0 + + # ---------- Build ---------- + def _build_pid_map_and_spawn(self): + """ + Baut Cortex, dann alle Neuronen (mit cx_pid=self.cx_actor), dann verlinkt Outputs schichtweise, + dann Sensoren/Aktuatoren (mit cx_pid=self.cx_actor). Achtung: Reihenfolge wichtig. + """ + cx = self.g["cortex"] + # Cortex zuerst (damit wir cx_pid an Kinder übergeben können) + self.cx_actor = Cortex( + cid=cx["id"], + exoself_pid=self, + sensor_pids=[], # werden gleich gesetzt + neuron_pids=[], + actuator_pids=[] + ) + + self.actuator_scape = XorScape() + + # Neuronen nach Layer gruppieren (damit outputs korrekt gesetzt werden) + layers: Dict[int, List[Dict[str, Any]]] = defaultdict(list) + for n in self.g["neurons"]: + layers[n["layer_index"]].append(n) + ordered_layers = [layers[i] for i in sorted(layers)] + + # Platzhalter: wir benötigen später Referenzen nach ID + id2neuron_actor: Dict[Any, Neuron] = {} + + # Zuerst alle Neuronen erzeugen (ohne Outputs), damit wir Referenzen haben + for layer in ordered_layers: + for n in layer: + input_idps = [(iw["input_id"], iw["weights"]) for iw in n["input_weights"]] + neuron = Neuron( + nid=n["id"], + cx_pid=self.cx_actor, + af_name=n.get("activation_function", "tanh"), + input_idps=input_idps, + output_pids=[] # füllen wir gleich + ) + id2neuron_actor[n["id"]] = neuron + self.neuron_actors.append(neuron) + + # Jetzt Outputs pro Layer setzen: + # - für Nicht-Output-Layer: Outputs = Neuronen der nächsten Schicht + # - für Output-Layer: Outputs = Aktuator(en) (setzen wir nachdem Aktuatoren erzeugt sind) + for li in range(len(ordered_layers) - 1): + next_pids = [id2neuron_actor[nx["id"]] for nx in ordered_layers[li + 1]] + for n in ordered_layers[li]: + id2neuron_actor[n["id"]].outputs = next_pids + + # Aktuatoren anlegen (brauchen cx_pid und fanin_ids) + # Genotyp kann "actuator" (ein Objekt) oder "actuators" (Liste) haben – wir unterstützen beides. + actuators = self._get_actuators_block() + if not actuators: + raise ValueError("Genotype must include 'actuator' or 'actuators'.") + + for a in actuators: + fanin_ids = a.get("fanin_ids", []) + expect = len(fanin_ids) if fanin_ids else 0 + actuator = Actuator( + aid=a["id"], + cx_pid=self.cx_actor, + name=a["name"], + fanin_ids=fanin_ids, + expect_count=expect, + scape=self.actuator_scape + ) + self.actuator_actors.append(actuator) + + # Output-Layer Neuronen → Outputs = Aktuatoren + if ordered_layers: + last_layer = ordered_layers[-1] + out_targets = self.actuator_actors # Liste + for n in last_layer: + id2neuron_actor[n["id"]].outputs = out_targets + + # Sensor(en) anlegen (brauchen cx_pid und fanout auf erste Schicht) + sensors = self._get_sensors_block() + if not sensors: + raise ValueError("Genotype must include 'sensor' or 'sensors'.") + + first_layer = ordered_layers[0] if ordered_layers else [] + first_layer_pids = [id2neuron_actor[n["id"]] for n in first_layer] + + for s in sensors: + sensor = Sensor( + sid=s["id"], + cx_pid=self.cx_actor, + name=s["name"], + vector_length=s["vector_length"], + fanout_pids=first_layer_pids, + scape=self.actuator_scape + ) + self.sensor_actors.append(sensor) + + def _get_sensors_block(self) -> List[Dict[str, Any]]: + if "sensors" in self.g: + return list(self.g["sensors"]) + if "sensor" in self.g: + return [self.g["sensor"]] + return [] + + def _get_actuators_block(self) -> List[Dict[str, Any]]: + if "actuators" in self.g: + return list(self.g["actuators"]) + if "actuator" in self.g: + return [self.g["actuator"]] + return [] + + # ---------- Link ---------- + def _link_cortex(self): + """ + Übergibt dem Cortex die fertigen Listen und setzt awaiting_sync. + Startet dann den Cortex-Task. + """ + self.cx_actor.sensors = [a for a in self.sensor_actors if a] + self.cx_actor.neurons = [a for a in self.neuron_actors if a] + self.cx_actor.actuators = [a for a in self.actuator_actors if a] + + # Wichtig: vor Start die erwarteten AIDs setzen, + # damit der erste Sensor-Trigger nicht in eine leere awaiting_sync läuft. + self.cx_actor.awaiting_sync = set(a.aid for a in self.cx_actor.actuators) + + # Cortex starten + self.tasks.append(asyncio.create_task(self.cx_actor.run())) + + # ---------- Training-Loop Reaction ---------- + async def _on_evaluation_completed(self, fitness: float, cycles: int, elapsed: float): + self.eval_acc += 1 + self.cycle_acc += int(cycles) + self.time_acc += float(elapsed) + + print(f"[Exoself] evaluation_completed: fitness={fitness:.6f} cycles={cycles} time={elapsed:.3f}s") + + if fitness > self.highest_fitness: + self.highest_fitness = fitness + self.attempt = 0 + # Backup aller Neuronen + for n in self.neuron_actors: + await n.send(("weight_backup",)) + else: + self.attempt += 1 + # Restore nur der zuletzt perturbierten Neuronen + for n in self._perturbed: + await n.send(("weight_restore",)) + + # Stop-Kriterium? + if self.attempt >= self.MAX_ATTEMPTS: + print(f"[Exoself] STOP. Best fitness={self.highest_fitness:.6f} evals={self.eval_acc} cycles={self.cycle_acc}") + await self._backup_genotype() + await self._terminate_all() + return { + "best_fitness": self.highest_fitness, + "eval_acc": self.eval_acc, + "cycle_acc": self.cycle_acc, + "time_acc": self.time_acc, + } + + # Perturbiere Teilmenge der Neuronen + tot = len(self.neuron_actors) + mp = 1.0 / math.sqrt(max(1, tot)) + self._perturbed = [n for n in self.neuron_actors if random.random() < mp] + + for n in self._perturbed: + await n.send(("weight_perturb",)) + + # Nächste Episode starten + await self.cx_actor.send(("reactivate",)) + + # ---------- Backup Genotype ---------- + async def _backup_genotype(self): + """ + Holt von allen Neuronen die aktuellen Weights und schreibt sie in self.g. + Speichert optional in self.file_name. + """ + # 1) Request + remaining = len(self.neuron_actors) + for n in self.neuron_actors: + await n.send(("get_backup",)) + + # 2) Collect vom Cortex-Postfach (Neuronen senden an cx_pid → cx leitet an Exoself weiter + # oder du hast sie direkt an Exoself schicken lassen; falls direkt an Cortex, dann + # lausche hier stattdessen auf self.cx_actor.inbox. In deinem Neuron-Code geht es an cx_pid, + # und in deiner bisherigen Implementierung hast du aus dem Cortex-Postfach gelesen. + # Hier vereinfachen wir: Neuronen senden direkt an EXOSELF (passe Neuron ggf. an). + backups: List[Tuple[Any, List[Tuple[Any, List[float]]]]] = [] + + while remaining > 0: + msg = await self.inbox.get() + if msg[0] == "backup_from_neuron": + _, nid, idps = msg + backups.append((nid, idps)) + remaining -= 1 + + # 3) Update JSON + # exoself.py -> in _backup_genotype() + id2n = {n["id"]: n for n in self.g["neurons"]} + for nid, idps in backups: + if nid not in id2n: + continue + new_iw = [] + bias_val = None + for item in idps: + if isinstance(item[0], str) and item[0] == "bias": + bias_val = float(item[1]) if not isinstance(item[1], list) else float(item[1][0]) + else: + input_id, weights = item + new_iw.append({"input_id": input_id, "weights": list(weights)}) + id2n[nid]["input_weights"] = new_iw + # Bias mit abspeichern (Variante B): + if bias_val is not None: + id2n[nid].setdefault("input_weights", []).append({"input_id": "bias", "weights": [bias_val]}) + + # 4) Save + if self.file_name: + with open(self.file_name, "w") as f: + json.dump(self.g, f, indent=2) + print(f"[Exoself] Genotype updated → {self.file_name}") + + # ---------- Termination ---------- + async def _terminate_all(self): + for a in self.sensor_actors + self.neuron_actors + self.actuator_actors: + await a.send(("terminate",)) + if self.cx_actor: + await self.cx_actor.send(("terminate",)) + for t in self.tasks: + if not t.done(): + t.cancel() + self.tasks.clear() diff --git a/experiments/stochastic_hillclimber/actors/experimental.json b/experiments/stochastic_hillclimber/actors/experimental.json new file mode 100644 index 0000000..286fe5e --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/experimental.json @@ -0,0 +1,96 @@ +{ + "cortex": { + "id": 0.0873421806271496, + "sensor_ids": [ + 5.6856379409509e-10 + ], + "actuator_ids": [ + 5.685637940950896e-10 + ], + "neuron_ids": [ + 0.6384794610574114, + 0.6023131059017351, + 0.39277072802910173 + ] + }, + "sensor": { + "id": 5.6856379409509e-10, + "name": "xor_GetInput", + "vector_length": 2, + "cx_id": 0.0873421806271496, + "fanout_ids": [ + 0.6384794610574114, + 0.6023131059017351 + ] + }, + "actuator": { + "id": 5.685637940950896e-10, + "name": "xor_SendOutput", + "vector_length": 1, + "cx_id": 0.0873421806271496, + "fanin_ids": [ + 0.39277072802910173 + ] + }, + "neurons": [ + { + "id": 0.6384794610574114, + "layer_index": 0, + "cx_id": 0.0873421806271496, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.6856379409509e-10, + "weights": [ + -1.241701053140722, + -0.9643293453192259 + ] + } + ], + "output_ids": [ + 0.20086494757397733 + ] + }, + { + "id": 0.6023131059017351, + "layer_index": 0, + "cx_id": 0.0873421806271496, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.6856379409509e-10, + "weights": [ + -0.38795737506820904, + -0.5125123920689245 + ] + } + ], + "output_ids": [ + 0.20086494757397733 + ] + }, + { + "id": 0.39277072802910173, + "layer_index": 1, + "cx_id": 0.0873421806271496, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.6384794610574114, + "weights": [ + -0.7426574958298033 + ] + }, + { + "input_id": 0.6023131059017351, + "weights": [ + -0.9823211499227558 + ] + } + ], + "output_ids": [ + 5.685637940950896e-10 + ] + } + ] +} \ No newline at end of file diff --git a/experiments/stochastic_hillclimber/actors/genotype.py b/experiments/stochastic_hillclimber/actors/genotype.py new file mode 100644 index 0000000..188b81f --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/genotype.py @@ -0,0 +1,266 @@ +# genotype.py +import json +import math +import random +import time +from typing import Dict, List, Tuple, Any, Optional + + +# ----------------------------- +# Utilities / ID & Weights +# ----------------------------- +def generate_id() -> float: + return random.random() + + +def create_neural_weights(vector_length: int) -> List[float]: + return [random.uniform(-2.0, 2.0) for _ in range(vector_length)] + + +# ----------------------------- +# Morphology "Interface" +# ----------------------------- +""" +Erwartete Morphologie-API (duck-typed): + +- get_InitSensor(morphology) -> dict mit Feldern: + { + "id": , + "name": , + "vector_length": , + # optional: "scape": , + } + +- get_InitActuator(morphology) -> dict mit Feldern: + { + "id": , + "name": , + "vector_length": , + # optional: "scape": , + } + +Du kannst z.B. ein kleines Modul/Objekt übergeben, das diese Funktionen bereitstellt. +""" + + +# ----------------------------- +# Genotype-Erzeugung +# ----------------------------- +def construct( + morphology_module, + hidden_layer_densities: List[int], + file_name: Optional[str] = None, + *, + add_bias: bool = False, +) -> Dict[str, Any]: + """ + Baut einen Genotyp (JSON-kompatibles Dict) analog zur Erlang-Version: + + - wählt Initial-Sensor & -Aktuator aus Morphologie + - bestimmt Output-Layer-Dichte = actuator.vector_length + - erzeugt alle Neuronen-Schichten & Gewichte + - setzt fanout_ids/fanin_ids + - erstellt Cortex mit Listen der IDs + - speichert optional in file_name + + add_bias: Wenn True, hängt pro Neuron einen Bias als ('bias', b) an die Input-Liste an. + Dein bisheriges JSON nutzt KEIN Bias-Element. Standard=False für Kompatibilität. + """ + + # Seed wie im Buch + rnd_seed = time.time_ns() & 0xFFFFFFFF + random.seed(rnd_seed) + + # 1) Sensor & Aktuator aus Morphologie + S = morphology_module.get_InitSensor(morphology_module) + A = morphology_module.get_InitActuator(morphology_module) + + # Pflichtfelder normalisieren + sensor = { + "id": S.get("id", generate_id()), + "name": S["name"], + "vector_length": int(S["vector_length"]), + "cx_id": None, # wird später gesetzt + "fanout_ids": [], # wird später gesetzt + # optional: + # "scape": S.get("scape") + } + + actuator = { + "id": A.get("id", generate_id()), + "name": A["name"], + "vector_length": int(A["vector_length"]), + "cx_id": None, # wird später gesetzt + "fanin_ids": [], # wird später gesetzt + # optional: + # "scape": A.get("scape") + } + + # 2) Output-Layer-Dichte = actuator.vector_length (wie im Buch) + output_vl = actuator["vector_length"] + layer_densities = list(hidden_layer_densities) + [output_vl] + + # 3) Cortex-ID festlegen + cortex_id = generate_id() + + # 4) Neuronen-Schichten erzeugen + layers = _create_neuro_layers( + cx_id=cortex_id, + sensor=sensor, + actuator=actuator, + layer_densities=layer_densities, + add_bias=add_bias, + ) + + # 5) Sensor/Aktuator mit Cortex/Fanout/Fanin verbinden + input_layer = layers[0] + output_layer = layers[-1] + + sensor["cx_id"] = cortex_id + sensor["fanout_ids"] = [n["id"] for n in input_layer] + + actuator["cx_id"] = cortex_id + actuator["fanin_ids"] = [n["id"] for n in output_layer] + + # 6) Cortex-Objekt + neuron_ids = [n["id"] for layer in layers for n in layer] + cortex = { + "id": cortex_id, + "sensor_ids": [sensor["id"]], + "actuator_ids": [actuator["id"]], + "neuron_ids": neuron_ids, + } + + # 7) Genotyp zusammensetzen + genotype = { + "cortex": cortex, + "sensor": sensor, + "actuator": actuator, + "neurons": [n for layer in layers for n in layer], + } + + # 8) Optional speichern + if file_name: + save_genotype(file_name, genotype) + + return genotype + + +def _create_neuro_layers( + cx_id: float, + sensor: Dict[str, Any], + actuator: Dict[str, Any], + layer_densities: List[int], + *, + add_bias: bool, +) -> List[List[Dict[str, Any]]]: + """ + Baut alle Neuronen-Schichten. + - Erste Schicht erhält als Input den Sensor (Vektor). + - Mittlere Schichten erhalten skalare Inputs von voriger Schicht. + - Letzte Schicht verbindet zum Aktuator (output_ids = [actuator.id]). + """ + layers: List[List[Dict[str, Any]]] = [] + + # Platzhalter-Input: (input_id, vector_length) + input_idps: List[Tuple[float, int]] = [(sensor["id"], sensor["vector_length"])] + + for layer_index, layer_density in enumerate(layer_densities): + # Neuron-IDs generieren + neuron_ids = [generate_id() for _ in range(layer_density)] + + # output_ids: Standardmäßig IDs der nächsten Schicht (werden nach dem Layer bekannt) + if layer_index < len(layer_densities) - 1: + # IDs der nächste Schicht vorab erzeugen (für output_ids) + next_ids = [generate_id() for _ in range(layer_densities[layer_index + 1])] + # Aber: wir erzeugen hier *nur* die IDs für output_ids, nicht die Neuronen der nächsten Schicht + output_ids = next_ids + else: + # letzte Schicht → zum Aktuator + output_ids = [actuator["id"]] + + # Layer-Neuronen erzeugen + this_layer: List[Dict[str, Any]] = [] + for _nid in neuron_ids: + proper_input = _create_neural_input(input_idps, add_bias=add_bias) + neuron = { + "id": _nid, + "layer_index": layer_index, + "cx_id": cx_id, + "activation_function": "tanh", + # JSON-Konvention: [{"input_id": id, "weights": [...]}, ...] + "input_weights": [{"input_id": i, "weights": w} for (i, w) in proper_input if not _is_bias_tuple((i, w))], + "output_ids": output_ids[:], # Kopie + } + this_layer.append(neuron) + + layers.append(this_layer) + + # Inputs für nächste Schicht: jetzt sind es skalare Outputs der aktuellen Neuronen + input_idps = [(n["id"], 1) for n in this_layer] + + # WICHTIG: oben haben wir für mittlere Layer „künstliche“ next_ids erzeugt, damit output_ids befüllt waren. + # In deiner Laufzeit-Topologie ignorieren wir diese Platzhalter und verdrahten später im Exoself die + # tatsächlichen Actor-Referenzen schichtweise. Für den Genotyp sind die output_ids der Zwischenlayer + # nicht kritisch (du überschreibst sie ohnehin beim Phenotype-Mapping). Die letzte Schicht zeigt korrekt auf den Aktuator. + + return layers + + +def _is_bias_tuple(t: Tuple[Any, Any]) -> bool: + """Hilfsfunktion falls du später Bias im JSON aufnehmen willst.""" + key, _ = t + return isinstance(key, str) and key == "bias" + + +def _create_neural_input( + input_idps: List[Tuple[float, int]], + *, + add_bias: bool, +) -> List[Tuple[Any, List[float]]]: + """ + Wandelt Platzhalter (input_id, vector_length) in (input_id, weights[]) um. + Optional einen Bias als ('bias', [b]) anhängen (Erlang-Variante). + """ + proper: List[Tuple[Any, List[float]]] = [] + for input_id, vl in input_idps: + proper.append((input_id, create_neural_weights(vl))) + + if add_bias: + proper.append(("bias", [random.random() - 0.5])) + + return proper + + +# ----------------------------- +# File I/O & Print +# ----------------------------- +def save_genotype(file_name: str, genotype: Dict[str, Any]) -> None: + with open(file_name, "w") as f: + json.dump(genotype, f, indent=2) + + +def load_from_file(file_name: str) -> Dict[str, Any]: + with open(file_name, "r") as f: + return json.load(f) + + +def print_genotype(file_name: str) -> None: + g = load_from_file(file_name) + cx = g["cortex"] + print("[CORTEX]", cx) + sids = cx.get("sensor_ids", []) + nids = cx.get("neuron_ids", []) + aids = cx.get("actuator_ids", []) + + # Indexe für schnellen Zugriff + nid2n = {n["id"]: n for n in g.get("neurons", [])} + sid2s = {g["sensor"]["id"]: g["sensor"]} if "sensor" in g else {s["id"]: s for s in g.get("sensors", [])} + aid2a = {g["actuator"]["id"]: g["actuator"]} if "actuator" in g else {a["id"]: a for a in g.get("actuators", [])} + + for sid in sids: + print("[SENSOR]", sid2s.get(sid)) + for nid in nids: + print("[NEURON]", nid2n.get(nid)) + for aid in aids: + print("[ACTUATOR]", aid2a.get(aid)) diff --git a/experiments/stochastic_hillclimber/actors/morphology.py b/experiments/stochastic_hillclimber/actors/morphology.py new file mode 100644 index 0000000..688f409 --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/morphology.py @@ -0,0 +1,104 @@ +# morphology.py +import time +from typing import Any, Callable, Dict, List, Union + +MorphologyType = Union[str, Callable[[str], List[Dict[str, Any]]]] + + +def generate_id() -> float: + """ + Zeitbasierte float-ID (ähnlich wie im Buch). + """ + now = time.time() + return 1.0 / now + + +# ------------------------------------------------------------ +# Morphologie-API (duck-typed, wie im Erlang-Original) +# ------------------------------------------------------------ +def get_InitSensor(morphology: MorphologyType) -> Dict[str, Any]: + sensors = get_Sensors(morphology) + if not sensors: + raise ValueError("Morphology has no sensors.") + return sensors[0] + + +def get_InitActuator(morphology: MorphologyType) -> Dict[str, Any]: + actuators = get_Actuators(morphology) + if not actuators: + raise ValueError("Morphology has no actuators.") + return actuators[0] + + +def get_Sensors(morphology: MorphologyType) -> List[Dict[str, Any]]: + fn = _resolve_morphology(morphology) + return fn("sensors") + + +def get_Actuators(morphology: MorphologyType) -> List[Dict[str, Any]]: + fn = _resolve_morphology(morphology) + return fn("actuators") + + +def _resolve_morphology(morphology: MorphologyType) -> Callable[[str], List[Dict[str, Any]]]: + """ + Akzeptiert: + - eine Callable Morphologie-Funktion (z.B. xor_mimic) + - einen String (z.B. "xor_mimic") -> per Registry auflösen + - ein Modul-Objekt (z.B. import morphology) -> Standard 'xor_mimic' aus dem Modul + """ + # 1) Bereits eine Callable-Funktion? (z.B. xor_mimic) + if callable(morphology): + return morphology + + # 2) String -> Registry + if isinstance(morphology, str): + reg = { + "xor_mimic": xor_mimic, + # weitere Morphologien hier registrieren... + } + if morphology in reg: + return reg[morphology] + raise ValueError(f"Unknown morphology name: {morphology}") + + # 3) Modul-Objekt: versuche eine Standard-Morphologie-Funktion daraus zu nehmen + # Hier nehmen wir 'xor_mimic' als Default (du kannst das generalisieren). + try: + # Ist es ein Modul mit einer Funktion 'xor_mimic'? + if hasattr(morphology, "xor_mimic") and callable(getattr(morphology, "xor_mimic")): + return getattr(morphology, "xor_mimic") + except Exception: + pass + + raise TypeError("morphology must be a callable, a module with 'xor_mimic', or a registered string key") + + +# ------------------------------------------------------------ +# Beispiel-Morphologie: XOR (wie im Buch) +# ------------------------------------------------------------ +def xor_mimic(kind: str) -> List[Dict[str, Any]]: + """ + Liefert je nach 'kind' ('sensors' | 'actuators') die Definitionen. + Felder sind so benannt, dass sie direkt mit unserem Genotype/Phenotype-Code + kompatibel sind (vector_length statt 'vl', etc.). + """ + if kind == "sensors": + return [ + { + "id": generate_id(), + "name": "xor_GetInput", # Sensorfunktion (muss in deinem Sensor-Actor implementiert sein) + "vector_length": 2, + "scape": {"private": "xor_sim"} # optional, falls du Scapes nutzt + } + ] + elif kind == "actuators": + return [ + { + "id": generate_id(), + "name": "xor_SendOutput", # Aktuatorfunktion (muss in deinem Actuator-Actor implementiert sein) + "vector_length": 1, + "scape": {"private": "xor_sim"} # optional + } + ] + else: + raise ValueError(f"xor_mimic: unsupported kind '{kind}', expected 'sensors' or 'actuators'") diff --git a/experiments/stochastic_hillclimber/actors/mtest.py b/experiments/stochastic_hillclimber/actors/mtest.py new file mode 100644 index 0000000..775ce8c --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/mtest.py @@ -0,0 +1,39 @@ +import asyncio + +import morphology +from experiments.stochastic_hillclimber.actors.trainer import Trainer +from genotype import construct, save_genotype + + +def test_genotype_construction(): + """ + genotype_data = construct(morphology, hidden_layer_densities=[3, 2]) + + # Prüfen, ob Cortex, Sensor, Actuator und Neuronen existieren + assert "cortex" in genotype_data + assert len(genotype_data["neurons"]) == 3 + 2 + 1 # 3 in 1. HL, 2 in 2. HL, 1 Output + + print("Genotype construction OK") + print("Cortex:", genotype_data["cortex"]) + print("---------------------------------") + print("Neurons:", genotype_data["neurons"]) + print("---------------------------------") + print("Actuators:", genotype_data["actuator"]) + + save_genotype("test.json", genotype_data) + """ + + trainer = Trainer( + morphology_spec=morphology, # <— wichtig! callable oder "xor_mimic" + hidden_layer_densities=[2], # wie im Buchbeispiel + max_attempts=float("inf"), # MA=inf + eval_limit=float("inf"), # EL=inf + fitness_target=99.9, # FT=99.9 + experimental_file="experimental.json", + best_file="best.json", + exoself_steps_per_eval=0, # 0 = Scape/Cortex entscheiden über Halt + ) + asyncio.run(trainer.go()) + + +test_genotype_construction() diff --git a/experiments/stochastic_hillclimber/actors/neuron.py b/experiments/stochastic_hillclimber/actors/neuron.py new file mode 100644 index 0000000..14c488c --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/neuron.py @@ -0,0 +1,105 @@ +# actors/neuron.py +import math +import random + +from actor import Actor + + +def tanh(x): return math.tanh(x) + + +class Neuron(Actor): + def __init__(self, nid, cx_pid, af_name, input_idps, output_pids): + super().__init__(f"Neuron-{nid}") + self.nid = nid + self.cx_pid = cx_pid + self.af = tanh if af_name == "tanh" else tanh + # input_idps: [(input_id, [w1, w2, ...])] + self.inputs = {} + self.order = [] + for (inp_id, weights) in input_idps: + self.order.append(inp_id) + self.inputs[inp_id] = {"weights": list(weights), "got": False, "val": None} + # WICHTIG: Bias lernbar machen + self.bias = random.uniform(-2.0, 2.0) + # Für Backup/Restore + self._backup_inputs = None + self._backup_bias = None + + self.outputs = output_pids + + print(f"Neuron {nid}: inputs={list(self.inputs.keys())}, bias={self.bias}") + + async def run(self): + while True: + msg = await self.inbox.get() + tag = msg[0] + + if tag == "forward": + _, from_id, data = msg + if from_id not in self.inputs: + continue + slot = self.inputs[from_id] + slot["got"] = True + slot["val"] = data + + if all(self.inputs[i]["got"] for i in self.order): + acc = 0.0 + for i in self.order: + w = self.inputs[i]["weights"] + v = self.inputs[i]["val"] + if isinstance(v, list): + acc += sum(wj * vj for wj, vj in zip(w, v)) + else: + acc += w[0] * float(v) + out = self.af(acc + self.bias) + for pid in self.outputs: + await pid.send(("forward", self.nid, [out])) + for i in self.order: + self.inputs[i]["got"] = False + self.inputs[i]["val"] = None + print(f"Neuron {self.nid}: input_sum={acc + self.bias:.3f}, output={out:.3f}") + + elif tag == "get_backup": + # Packe Gewichte + Bias zurück + idps = [(i, self.inputs[i]["weights"]) for i in self.order] + idps.append(("bias", self.bias)) + await self.cx_pid.send(("backup_from_neuron", self.nid, idps)) + + elif tag == "weight_backup": + # Tiefkopie der Gewichte + Bias + print(f"Neuron {self.nid}: backing up weights") + self._backup_inputs = {k: {"weights": v["weights"][:]} for k, v in self.inputs.items()} + self._backup_bias = self.bias + + elif tag == "weight_restore": + if self._backup_inputs is not None: + for k in self.inputs: + self.inputs[k]["weights"] = self._backup_inputs[k]["weights"][:] + self.bias = self._backup_bias + + elif tag == "weight_perturb": + # In neuron.py weight_perturb, add: + print(f"Neuron {self.nid}: perturbing {len([w for i in self.order for w in self.inputs[i]['weights']])} weights") + # MP wie im Buch: 1/sqrt(TotalWeightsIncludingBias) + tot_w = sum(len(self.inputs[i]["weights"]) for i in self.order) + 1 + mp = 1 / math.sqrt(tot_w) + delta_mag = 2.0 * math.pi + sat_lim = 2.0 * math.pi + + # Gewichte perturbieren + for i in self.order: + ws = self.inputs[i]["weights"] + for j in range(len(ws)): + if random.random() < mp: + ws[j] = _sat(ws[j] + (random.random() - 0.5) * delta_mag, -sat_lim, sat_lim) + # Bias perturbieren + if random.random() < mp: + self.bias = _sat(self.bias + (random.random() - 0.5) * delta_mag, -sat_lim, sat_lim) + + elif tag == "terminate": + return + + +def _sat(val, lo, hi): + return lo if val < lo else (hi if val > hi else val) diff --git a/experiments/stochastic_hillclimber/actors/scape.py b/experiments/stochastic_hillclimber/actors/scape.py new file mode 100644 index 0000000..95afe57 --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/scape.py @@ -0,0 +1,58 @@ +# actors/scape.py +from actor import Actor +import math + + +class XorScape(Actor): + def __init__(self): + super().__init__("XorScape") + self.data = [ + ([-1, -1], [-1]), + ([1, -1], [1]), + ([-1, 1], [1]), + ([1, 1], [-1]) + ] + self.index = 0 + self.error_acc = 0.0 + self.last_actuator = None # <-- wer uns zuletzt "action" geschickt hat + + async def run(self): + while True: + msg = await self.inbox.get() + tag = msg[0] + + if tag == "sense": + print("SCAPE: got sensed by sensor...") + # Sensor fragt nach Input + _, sid, from_pid = msg + self.last_actuator = from_pid # merken, wer beteiligt ist + inputs, correct = self.data[self.index] + print("SENSOR input /correct: ", inputs, correct) + await from_pid.send(("percept", inputs)) + + elif tag == "action": + _, output, from_pid = msg + _, correct = self.data[self.index] + + # Calculate RMSE like the Erlang version + step_error = sum((o - c) ** 2 for o, c in zip(output, correct)) + step_rmse = math.sqrt(step_error) # This is the key change! + + print(f"XOR PATTERN: Input={self.data[self.index][0]} → Network={output} → Expected={correct}") + + self.index += 1 + + if self.index >= len(self.data): + # Episode finished - calculate final fitness + total_rmse = math.sqrt(self.error_acc + step_rmse) # Not step_error! + fitness = 1.0 / (total_rmse + 1e-5) + await from_pid.send(("result", fitness, 1)) + self.index = 0 + self.error_acc = 0.0 + else: + # Continue episode + self.error_acc += step_rmse # Add RMSE, not raw error + await from_pid.send(("result", 0.0, 0)) + + elif tag == "terminate": + return diff --git a/experiments/stochastic_hillclimber/actors/sensor.py b/experiments/stochastic_hillclimber/actors/sensor.py new file mode 100644 index 0000000..7ef72cb --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/sensor.py @@ -0,0 +1,45 @@ +# actors/sensor.py +from actor import Actor +import random + + +class Sensor(Actor): + def __init__(self, sid, cx_pid, name, vector_length, fanout_pids, scape=None): + super().__init__(f"Sensor-{sid}") + self.sid = sid + self.cx_pid = cx_pid + self.sname = name + self.vl = vector_length + self.fanout = fanout_pids + self.scape = scape + + async def run(self): + while True: + print("sensor running...") + msg = await self.inbox.get() + tag = msg[0] + + print("got sensor message: ", msg) + + if tag == "sync": + vec = await self._sense() + print("sensed vec: ", vec) + for pid in self.fanout: + await pid.send(("forward", self.sid, vec)) + + elif tag == "terminate": + return + + async def _sense(self): + if self.sname == "rng": + return [random.random() for _ in range(self.vl)] + elif self.sname == "xor_GetInput" and self.scape: + print("TODO") + await self.scape.send(("sense", self.sid, self)) + msg = await self.inbox.get() + if msg[0] == "percept": + return msg[1] + else: + return [0.0] * self.vl + else: + return [0.0] * self.vl diff --git a/experiments/stochastic_hillclimber/actors/test.json b/experiments/stochastic_hillclimber/actors/test.json new file mode 100644 index 0000000..959f5e1 --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/test.json @@ -0,0 +1,179 @@ +{ + "cortex": { + "id": 5.685689537782505e-10, + "sensor_ids": [ + 5.685689537782522e-10 + ], + "actuator_ids": [ + 5.685689537782516e-10 + ], + "neuron_ids": [ + 5.685689537782498e-10, + 5.685689537782496e-10, + 5.685689537782496e-10, + 5.685689537782457e-10, + 5.685689537782457e-10, + 5.685689537782437e-10 + ] + }, + "sensor": { + "id": 5.685689537782522e-10, + "name": "xor_GetInput", + "vector_length": 2, + "cx_id": 5.685689537782505e-10, + "fanout_ids": [ + 5.685689537782498e-10, + 5.685689537782496e-10, + 5.685689537782496e-10 + ] + }, + "actuator": { + "id": 5.685689537782516e-10, + "name": "xor_SendOutput", + "vector_length": 1, + "cx_id": 5.685689537782505e-10, + "fanin_ids": [ + 5.685689537782437e-10 + ] + }, + "neurons": [ + { + "id": 5.685689537782498e-10, + "layer_index": 0, + "cx_id": 5.685689537782505e-10, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685689537782522e-10, + "weights": [ + -0.16508088565795254, + -0.2129110085532152 + ] + } + ], + "output_ids": [ + 5.685689537782493e-10, + 5.685689537782493e-10 + ] + }, + { + "id": 5.685689537782496e-10, + "layer_index": 0, + "cx_id": 5.685689537782505e-10, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685689537782522e-10, + "weights": [ + -0.2097398020485577, + 0.39878180348846304 + ] + } + ], + "output_ids": [ + 5.685689537782493e-10, + 5.685689537782493e-10 + ] + }, + { + "id": 5.685689537782496e-10, + "layer_index": 0, + "cx_id": 5.685689537782505e-10, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685689537782522e-10, + "weights": [ + -0.29051024087142796, + 0.4799280128038572 + ] + } + ], + "output_ids": [ + 5.685689537782493e-10, + 5.685689537782493e-10 + ] + }, + { + "id": 5.685689537782457e-10, + "layer_index": 1, + "cx_id": 5.685689537782505e-10, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685689537782498e-10, + "weights": [ + -0.13139529896484625 + ] + }, + { + "input_id": 5.685689537782496e-10, + "weights": [ + 0.0922098630405015 + ] + }, + { + "input_id": 5.685689537782496e-10, + "weights": [ + 0.07506465172430998 + ] + } + ], + "output_ids": [ + 5.685689537782454e-10 + ] + }, + { + "id": 5.685689537782457e-10, + "layer_index": 1, + "cx_id": 5.685689537782505e-10, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685689537782498e-10, + "weights": [ + 0.01874150935077279 + ] + }, + { + "input_id": 5.685689537782496e-10, + "weights": [ + 0.1722685772992305 + ] + }, + { + "input_id": 5.685689537782496e-10, + "weights": [ + -0.07333424218267892 + ] + } + ], + "output_ids": [ + 5.685689537782454e-10 + ] + }, + { + "id": 5.685689537782437e-10, + "layer_index": 2, + "cx_id": 5.685689537782505e-10, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 5.685689537782457e-10, + "weights": [ + 0.47060152728694127 + ] + }, + { + "input_id": 5.685689537782457e-10, + "weights": [ + 0.33179877773351285 + ] + } + ], + "output_ids": [ + 5.685689537782516e-10 + ] + } + ] +} \ No newline at end of file diff --git a/experiments/stochastic_hillclimber/actors/trainer.py b/experiments/stochastic_hillclimber/actors/trainer.py new file mode 100644 index 0000000..24aeaca --- /dev/null +++ b/experiments/stochastic_hillclimber/actors/trainer.py @@ -0,0 +1,151 @@ +# trainer.py +import asyncio +import time +from typing import Any, Dict, List, Tuple, Optional + +import morphology # dein morphology.py +from genotype import construct, save_genotype, print_genotype +from exoself import Exoself # deine Actor-basierte Exoself-Implementierung + + +class Trainer: + """ + Stochastischer Hillclimber wie im Erlang-Original. + - morphology_spec: entweder das morphology-Modul, ein String-Key, oder eine Callable-Morphologie + - hidden_layer_densities: z.B. [4, 3] + - max_attempts / eval_limit / fitness_target: Stoppbedingungen + - experimental_file / best_file: Pfade, falls du wie im Buch speichern willst + """ + + def __init__( + self, + morphology_spec=morphology, + hidden_layer_densities: List[int] = None, + *, + max_attempts: int = 5, + eval_limit: float = float("inf"), + fitness_target: float = float("inf"), + experimental_file: Optional[str] = "experimental.json", + best_file: Optional[str] = "best.json", + exoself_steps_per_eval: int = 0, + ): + self.morphology_spec = morphology_spec + self.hds = hidden_layer_densities or [] + self.max_attempts = max_attempts + self.eval_limit = eval_limit + self.fitness_target = fitness_target + self.experimental_file = experimental_file + self.best_file = best_file + # Wenn deine Exoself/Cortex eine feste Anzahl Zyklen pro „Evaluation“ braucht, + # kannst du hier default 0 lassen (Cortex entscheidet über Halt-Flag), + # oder einen Wert setzen. + self.exoself_steps_per_eval = exoself_steps_per_eval + + # Laufende Akkus (wie im Erlang-Code) + self.best_fitness = float("-inf") + self.best_genotype: Optional[Dict[str, Any]] = None + + self.eval_acc = 0 + self.cycle_acc = 0 + self.time_acc = 0.0 + + async def _run_one_attempt(self) -> Tuple[float, int, int, float, Dict[str, Any]]: + """ + Ein Trainingsversuch: + - Genotyp konstruieren + - Exoself laufen lassen + - Fitness/Evals/Cycles/Time zurückgeben + den verwendeten Genotyp + """ + print("constructing genotype...") + geno = construct(self.morphology_spec, self.hds, file_name=self.experimental_file, add_bias=True) + + # Exoself starten und bis zum evaluation_completed warten + fitness, evals, cycles, elapsed = await self._evaluate_with_exoself(geno) + + return fitness, evals, cycles, elapsed, geno + + async def _evaluate_with_exoself(self, genotype: Dict[str, Any]) -> Tuple[float, int, int, float]: + """ + Startet Exoself (deine Actor-basierte Variante) und wartet, + bis der Cortex die Evaluation abgeschlossen hat. + Erwartete Rückgabe: fitness, evals, cycles, elapsed + """ + print("creating exoself...") + ex = Exoself(genotype) + # Exoself.run() sollte idealerweise einen Tuple (fitness, evals, cycles, time) + # liefern. Falls deine Version aktuell „backup“-Listen liefert, ersetze das hier + # mit der passenden Logik oder benutze das „evaluation_completed“-Signal aus dem Cortex. + fitness, evals, cycles, elapsed = await ex.run_evaluation() + return fitness, evals, cycles, elapsed + + async def go(self): + """ + Entspricht dem Erlang loop/…: + Wiederholt Versuche, bis Stoppbedingung erfüllt. + """ + attempt = 1 + while True: + print(".........") + print("current attempt: ", attempt) + print(".........") + # Stoppbedingung vor Versuch? + if attempt > self.max_attempts or self.eval_acc >= self.eval_limit or self.best_fitness >= self.fitness_target: + # Ausgabe wie im Buch + if self.best_genotype and self.best_file: + # bestes Genotypfile ausgeben/„drucken“ + save_genotype(self.best_file, self.best_genotype) + print_genotype(self.best_file) + print( + f" Morphology: {getattr(self.morphology_spec, '__name__', str(self.morphology_spec))} | " + f"Best Fitness: {self.best_fitness} | EvalAcc: {self.eval_acc}" + ) + # Optional: an „Benchmarker“ melden – bei dir vermutlich nicht nötig + return { + "best_fitness": self.best_fitness, + "eval_acc": self.eval_acc, + "cycle_acc": self.cycle_acc, + "time_acc": self.time_acc, + "best_file": self.best_file, + } + + print("RUN ONE ATTEMPT!") + # --- Ein Versuch --- + fitness, evals, cycles, elapsed, geno = await self._run_one_attempt() + + print("update akkus...") + + # Akkus updaten + self.eval_acc += evals + self.cycle_acc += cycles + self.time_acc += elapsed + + # Besser als bisher? + if fitness > self.best_fitness: + # „experimental.json“ → „best.json“ (semantisch wie file:rename(...)) + self.best_fitness = fitness + self.best_genotype = geno + if self.best_file: + save_genotype(self.best_file, geno) + # Reset Attempt-Zähler (wie Erlang: Attempt=0 nach Verbesserung) + attempt = 1 + else: + attempt += 1 + + +# -------------------------- +# Beispiel: ausführen +# -------------------------- +if __name__ == "__main__": + # Beispielkonfiguration (XOR-Morphologie, kleine Topologie) + trainer = Trainer( + morphology_spec=morphology, # oder morphology.xor_mimic + hidden_layer_densities=[2], # wie im Buch-Beispiel + max_attempts=1000, + eval_limit=float("inf"), + fitness_target=float("inf"), + experimental_file="experimental.json", + best_file="best.json", + exoself_steps_per_eval=0, # 0 => Cortex/Scape steuern Halt-Flag + ) + + asyncio.run(trainer.go()) diff --git a/experiments/stochastic_hillclimber/run.py b/experiments/stochastic_hillclimber/run.py new file mode 100644 index 0000000..e69de29