From 0ad84365e4b002fefbe08930c452173db825a6cd Mon Sep 17 00:00:00 2001 From: Morten Rohgalf Date: Wed, 24 Sep 2025 09:45:17 +0200 Subject: [PATCH] initial. --- .DS_Store | Bin 0 -> 6148 bytes experiments/genotype.json | 258 +++++++++++++++++++++++++++++++++ experiments/genotype_mapper.py | 196 +++++++++++++++++++++++++ experiments/neuron.py | 55 +++++++ experiments/simplest_nn.py | 130 +++++++++++++++++ 5 files changed, 639 insertions(+) create mode 100644 .DS_Store create mode 100644 experiments/genotype.json create mode 100644 experiments/genotype_mapper.py create mode 100644 experiments/neuron.py create mode 100644 experiments/simplest_nn.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..acafa6d96adea3a215dac438d7bb64a485f0e63f GIT binary patch literal 6148 zcmeHKOHRWu5FM8;T2-Km6&s|SAX0CTR$;-q2PpKT0!r$LP(gQDB5@dYT!C9~0#3jN z-gvAkO&TON2%#Bi{2XVV<9T-Cn25}1Js%MDiKqi-Y;{rWF}}}UvzBjRo^gHL(lw>D zpcUQKqP5{KD!_Bs!;C#phO#_=`FUbz)5J~@f#qQy;qy;tE|CUSvK)+OHqA=OHbka2 zj(z`~kC(Um_u=cXc{Hh={~$WMs*U21mTqNQtj&$fHl!QM$>4P&V_tC{Wv7j{+#`9CS_3Ky4Zs(>n> z3Vfpg_H4FJPf$x$Kow90whHj~A%HVR9t%PD=|JI*0KhhyouSTW3FZVIBaek3?!b&t zfkHL@h+%||_Q1zQ9t%OClktZS6fo_09FLHa-&HbR2> literal 0 HcmV?d00001 diff --git a/experiments/genotype.json b/experiments/genotype.json new file mode 100644 index 0000000..f762020 --- /dev/null +++ b/experiments/genotype.json @@ -0,0 +1,258 @@ +{ + "cortex": { + "id": 0.38985127736117664, + "sensor_ids": [ + 0.5481697495393968 + ], + "actuator_ids": [ + 0.300862433948894 + ], + "neuron_ids": [ + 0.7892266733003815, + 0.08993126065168999, + 0.7353679413901013, + 0.7986671199471203, + 0.2619274118215478, + 0.1878355172703, + 0.5460586524022121, + 0.0325156080072021 + ] + }, + "sensor": { + "id": 0.5481697495393968, + "name": "rng", + "vector_length": 2, + "cx_id": 0.37250552293263184, + "fanout_ids": [ + 0.7892266733003815, + 0.08993126065168999, + 0.7353679413901013, + 0.7986671199471203 + ] + }, + "actuator": { + "id": 0.300862433948894, + "name": "pts", + "vector_length": 1, + "cx_id": 0.37250552293263184, + "fanin_ids": [ + 0.0325156080072021 + ] + }, + "neurons": [ + { + "id": 0.7892266733003815, + "layer_index": 0, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.5481697495393968, + "weights": [ + -0.2010596737648036, + -0.017559575650012982 + ] + } + ], + "output_ids": [ + 0.11787440750922895, + 0.9473188607259506, + 0.9045741659912035 + ] + }, + { + "id": 0.08993126065168999, + "layer_index": 0, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.5481697495393968, + "weights": [ + 0.49425647147649876, + 0.09556856915703738 + ] + } + ], + "output_ids": [ + 0.11787440750922895, + 0.9473188607259506, + 0.9045741659912035 + ] + }, + { + "id": 0.7353679413901013, + "layer_index": 0, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.5481697495393968, + "weights": [ + -0.3432015569352376, + -0.15663876804924903 + ] + } + ], + "output_ids": [ + 0.11787440750922895, + 0.9473188607259506, + 0.9045741659912035 + ] + }, + { + "id": 0.7986671199471203, + "layer_index": 0, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.5481697495393968, + "weights": [ + 0.44235413103542676, + -0.3014661028473905 + ] + } + ], + "output_ids": [ + 0.11787440750922895, + 0.9473188607259506, + 0.9045741659912035 + ] + }, + { + "id": 0.2619274118215478, + "layer_index": 1, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.7892266733003815, + "weights": [ + 0.4815260544600901 + ] + }, + { + "input_id": 0.08993126065168999, + "weights": [ + -0.34742595611872107 + ] + }, + { + "input_id": 0.7353679413901013, + "weights": [ + 0.1955465593022997 + ] + }, + { + "input_id": 0.7986671199471203, + "weights": [ + 0.1420046463445398 + ] + } + ], + "output_ids": [ + 0.804289241732289 + ] + }, + { + "id": 0.1878355172703, + "layer_index": 1, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.7892266733003815, + "weights": [ + -0.26492297905129614 + ] + }, + { + "input_id": 0.08993126065168999, + "weights": [ + -0.483071194536965 + ] + }, + { + "input_id": 0.7353679413901013, + "weights": [ + 0.0016581996680702371 + ] + }, + { + "input_id": 0.7986671199471203, + "weights": [ + 0.47010344086613354 + ] + } + ], + "output_ids": [ + 0.804289241732289 + ] + }, + { + "id": 0.5460586524022121, + "layer_index": 1, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.7892266733003815, + "weights": [ + 0.22583100100162312 + ] + }, + { + "input_id": 0.08993126065168999, + "weights": [ + 0.22079487426614341 + ] + }, + { + "input_id": 0.7353679413901013, + "weights": [ + 0.3514718848950448 + ] + }, + { + "input_id": 0.7986671199471203, + "weights": [ + 0.03653443587296967 + ] + } + ], + "output_ids": [ + 0.804289241732289 + ] + }, + { + "id": 0.0325156080072021, + "layer_index": 2, + "cx_id": 0.37250552293263184, + "activation_function": "tanh", + "input_weights": [ + { + "input_id": 0.2619274118215478, + "weights": [ + 0.4397546856440344 + ] + }, + { + "input_id": 0.1878355172703, + "weights": [ + 0.024524621225712195 + ] + }, + { + "input_id": 0.5460586524022121, + "weights": [ + 0.19908558570374346 + ] + } + ], + "output_ids": [ + 0.300862433948894 + ] + } + ] +} \ No newline at end of file diff --git a/experiments/genotype_mapper.py b/experiments/genotype_mapper.py new file mode 100644 index 0000000..fcbf0d9 --- /dev/null +++ b/experiments/genotype_mapper.py @@ -0,0 +1,196 @@ +import json +import random +import math +from typing import List, Dict, Tuple + + +# ---- Hilfsfunktionen ---- +def generate_id(): + """Generiert eine eindeutige ID basierend auf Zufallszahlen.""" + return random.random() + + +def create_neural_weights(vector_length: int): + """Erstellt eine Liste von Gewichten für eine Verbindung.""" + return [random.uniform(-0.5, 0.5) for _ in range(vector_length)] + + +# ---- Klassen ---- +class Sensor: + def __init__(self, name: str, vector_length: int): + self.id = generate_id() + self.name = name + self.vector_length = vector_length + self.cx_id = None # Wird später hinzugefügt + self.fanout_ids = [] # Verbindungen zu Neuronen + + def to_dict(self): + return { + "id": self.id, + "name": self.name, + "vector_length": self.vector_length, + "cx_id": self.cx_id, + "fanout_ids": self.fanout_ids, + } + + +class Actuator: + def __init__(self, name: str, vector_length: int): + self.id = generate_id() + self.name = name + self.vector_length = vector_length + self.cx_id = None # Wird später hinzugefügt + self.fanin_ids = [] # Verbindungen von Neuronen + + def to_dict(self): + return { + "id": self.id, + "name": self.name, + "vector_length": self.vector_length, + "cx_id": self.cx_id, + "fanin_ids": self.fanin_ids, + } + + +class Neuron: + def __init__(self, layer_index: int, input_ids: List[Tuple[float, int]], output_ids: List[float], cx_id: float): + self.id = generate_id() + self.layer_index = layer_index + self.cx_id = cx_id + self.activation_function = "tanh" + self.input_weights = [ + {"input_id": input_id, "weights": create_neural_weights(vector_length)} + for input_id, vector_length in input_ids + ] + self.output_ids = output_ids + + def to_dict(self): + return { + "id": self.id, + "layer_index": self.layer_index, + "cx_id": self.cx_id, + "activation_function": self.activation_function, + "input_weights": self.input_weights, + "output_ids": self.output_ids, + } + + +class Cortex: + def __init__(self, sensor_ids: List[float], actuator_ids: List[float], neuron_ids: List[float]): + self.id = generate_id() + self.sensor_ids = sensor_ids + self.actuator_ids = actuator_ids + self.neuron_ids = neuron_ids + + def to_dict(self): + return { + "id": self.id, + "sensor_ids": self.sensor_ids, + "actuator_ids": self.actuator_ids, + "neuron_ids": self.neuron_ids, + } + + # ---- Hauptfunktionen ---- + + +def construct_genotype(sensor_name: str, actuator_name: str, hidden_layer_densities: List[int], file_name: str): + """ + Konstruktion eines Genotyps und Speicherung in einer JSON-Datei. + """ + # Sensor erstellen + if sensor_name == "rng": + sensor = Sensor(name="rng", vector_length=2) + else: + raise ValueError(f"System does not support a sensor by the name: {sensor_name}") + + # Aktuator erstellen + if actuator_name == "pts": + actuator = Actuator(name="pts", vector_length=1) + else: + raise ValueError(f"System does not support an actuator by the name: {actuator_name}") + + # Neuronenschichten erstellen + output_layer_density = actuator.vector_length + layer_densities = hidden_layer_densities + [output_layer_density] + cortex_id = generate_id() + + neurons = create_neuro_layers( + cortex_id, + sensor, + actuator, + layer_densities + ) + + # Sensor und Aktuator mit Cortex-Informationen aktualisieren + input_layer_neurons = neurons[0] + output_layer_neurons = neurons[-1] + + sensor.cx_id = cortex_id + sensor.fanout_ids = [neuron.id for neuron in input_layer_neurons] + + actuator.cx_id = cortex_id + actuator.fanin_ids = [neuron.id for neuron in output_layer_neurons] + + # Cortex erstellen + neuron_ids = [neuron.id for layer in neurons for neuron in layer] + cortex = Cortex( + sensor_ids=[sensor.id], + actuator_ids=[actuator.id], + neuron_ids=neuron_ids + ) + + # Genotyp erstellen + genotype = { + "cortex": cortex.to_dict(), + "sensor": sensor.to_dict(), + "actuator": actuator.to_dict(), + "neurons": [neuron.to_dict() for layer in neurons for neuron in layer] + } + + # Genotyp in Datei speichern + with open(file_name, "w") as file: + json.dump(genotype, file, indent=4) + print(f"Genotype saved to {file_name}") + + +def create_neuro_layers(cortex_id: float, sensor: Sensor, actuator: Actuator, layer_densities: List[int]) -> List[ + List[Neuron]]: + """ + Erstellt alle Neuronen in allen Schichten des Netzwerks. + """ + neurons = [] + input_ids = [(sensor.id, sensor.vector_length)] + + for layer_index, layer_density in enumerate(layer_densities): + output_ids = [] + if layer_index < len(layer_densities) - 1: + # IDs der nächsten Schicht generieren + output_ids = [generate_id() for _ in range(layer_densities[layer_index + 1])] + + # Neuronen für die aktuelle Schicht erstellen + layer_neurons = [ + Neuron(layer_index=layer_index, input_ids=input_ids, output_ids=output_ids, cx_id=cortex_id) + for _ in range(layer_density) + ] + neurons.append(layer_neurons) + + # Aktuelle Schicht wird die Eingabe für die nächste Schicht + input_ids = [(neuron.id, 1) for neuron in layer_neurons] + + # Letzte Schicht mit Verbindung zum Aktuator erstellen + final_layer = neurons[-1] + for neuron in final_layer: + neuron.output_ids = [actuator.id] + + return neurons + + +# ---- Beispielverwendung ---- +if __name__ == "__main__": + # Genotyp erstellen und speichern + construct_genotype( + sensor_name="rng", + actuator_name="pts", + hidden_layer_densities=[4,3], # Dichten der versteckten Schichten (z. B. 4 Neuronen in der ersten Schicht, 3 in der zweiten) + file_name="genotype.json" # Name der Datei, in der der Genotyp gespeichert wird + ) \ No newline at end of file diff --git a/experiments/neuron.py b/experiments/neuron.py new file mode 100644 index 0000000..b11cfc0 --- /dev/null +++ b/experiments/neuron.py @@ -0,0 +1,55 @@ +import random +import math + + +class SimpleNeuron: + def __init__(self): + # Initialisiere Gewichte und Bias mit Zufallswerten zwischen -0.5 und 0.5 + self.weights = [random.uniform(-0.5, 0.5) for _ in range(2)] + self.bias = random.uniform(-0.5, 0.5) + + def dot(self, input_vector): + """ + Berechnet das Skalarprodukt zwischen dem Eingabevektor und den Gewichten, + fügt den Bias hinzu und gibt das Ergebnis zurück. + """ + acc = sum(i * w for i, w in zip(input_vector, self.weights)) + return acc + self.bias + + def process_input(self, input_vector): + """ + Verarbeitet den Eingabevektor, berechnet den Dot-Produkt, + wendet die Aktivierungsfunktion (tanh) an und gibt das Ergebnis zurück. + """ + print("**** Processing ****") + print(f"Input: {input_vector}") + print(f"Using Weights: {self.weights} and Bias: {self.bias}") + + dot_product = self.dot(input_vector) + output = math.tanh(dot_product) + + print(f"Output: {output}") + return output + + +def sense(in_neuron, signal): + """ + Diese Funktion überprüft, ob das Signal eine Liste der Länge 2 ist, + und sendet es an das Neuron zur Verarbeitung. + """ + if isinstance(signal, list) and len(signal) == 2: + output = in_neuron.process_input(signal) + print(f"Final Output: {output}") + else: + print("The Signal must be a list of length 2") + + # Beispiel zur Verwendung: + + +if __name__ == "__main__": + # Erstelle ein Neuron + neuron = SimpleNeuron() + + # Sende ein Signal (Eingabevektor) an das Neuron + test_signal = [0.5, -0.3] # Beispiel-Eingabe + sense(neuron, test_signal) \ No newline at end of file diff --git a/experiments/simplest_nn.py b/experiments/simplest_nn.py new file mode 100644 index 0000000..a7f0216 --- /dev/null +++ b/experiments/simplest_nn.py @@ -0,0 +1,130 @@ +import random +import math +import threading +import queue + + +class Neuron(threading.Thread): + def __init__(self, weights, neuron_queue, actuator_queue): + super().__init__() + self.weights = weights + self.neuron_queue = neuron_queue + self.actuator_queue = actuator_queue + self.running = True + + def dot(self, input_vector): + acc = sum(i * w for i, w in zip(input_vector, self.weights[:-1])) + return acc + self.weights[-1] + + def run(self): + while self.running: + try: + message = self.neuron_queue.get(timeout=1) + if message[0] == "forward": + input_vector = message[1] + print("**** Thinking ****") + print(f"Input: {input_vector}") + print(f"With Weights: {self.weights}") + + dot_product = self.dot(input_vector) + output = [math.tanh(dot_product)] + + self.actuator_queue.put(("forward", output)) + elif message[0] == "terminate": + self.running = False + except queue.Empty: + continue + + +class Sensor(threading.Thread): + def __init__(self, sensor_queue, neuron_queue): + super().__init__() + self.sensor_queue = sensor_queue + self.neuron_queue = neuron_queue + self.running = True + + def run(self): + while self.running: + try: + message = self.sensor_queue.get(timeout=1) + if message == "sync": + sensory_signal = [random.uniform(0, 1), random.uniform(0, 1)] + print("**** Sensing ****") + print(f"Signal from the environment: {sensory_signal}") + + self.neuron_queue.put(("forward", sensory_signal)) + elif message == "terminate": + self.running = False + except queue.Empty: + continue + +class Actuator(threading.Thread): + def __init__(self, actuator_queue): + super().__init__() + self.actuator_queue = actuator_queue + self.running = True + + def pts(self, control_signal): + print("**** Acting ****") + print(f"Using: {control_signal} to act on the environment.") + + def run(self): + while self.running: + try: + message = self.actuator_queue.get(timeout=1) + if message[0] == "forward": + control_signal = message[1] + self.pts(control_signal) + elif message[0] == "terminate": + self.running = False + except queue.Empty: + continue + +class Cortex(threading.Thread): + def __init__(self, sensor_queue, neuron_queue, actuator_queue): + super().__init__() + self.sensor_queue = sensor_queue + self.neuron_queue = neuron_queue + self.actuator_queue = actuator_queue + self.running = True + + def run(self): + while self.running: + command = input("amna> ").strip() + if command == "sense_think_act": + self.sensor_queue.put("sync") + elif command == "terminate": + self.sensor_queue.put("terminate") + self.neuron_queue.put(("terminate",)) + self.actuator_queue.put(("terminate",)) + self.running = False + else: + print("Unknown command. Please use 'sense_think_act' or 'terminate'.") + print("Cortex terminated.") + +if __name__ == "__main__": + sensor_queue = queue.Queue() + neuron_queue = queue.Queue() + actuator_queue = queue.Queue() + + # initialize weights (including bias) + weights = [random.uniform(-0.5, 0.5) for _ in range(2)] + [random.uniform(-0.5, 0.5)] # Zwei Gewichte + Bias + + sensor = Sensor(sensor_queue, neuron_queue) + neuron = Neuron(weights, neuron_queue, actuator_queue) + actuator = Actuator(actuator_queue) + + sensor.start() + neuron.start() + actuator.start() + + cortex = Cortex(sensor_queue, neuron_queue, actuator_queue) + cortex.start() + + cortex.join() + + sensor.join() + neuron.join() + actuator.join() + + print("System terminated.") \ No newline at end of file