Files
neuroevolution/experiments/stochastic_hillclimber/actors/morphology.py

105 lines
3.6 KiB
Python

# 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'")