Rkruemmel commited on
Commit
02bfffc
·
verified ·
1 Parent(s): bf402f8

Upload main.py

Browse files
Files changed (1) hide show
  1. main.py +1667 -0
main.py ADDED
@@ -0,0 +1,1667 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import random
4
+ from tqdm import tqdm
5
+ import tkinter as tk
6
+ from tkinter import ttk, messagebox
7
+ import seaborn as sns
8
+ import networkx as nx
9
+ import json
10
+ import os
11
+ import time
12
+ import torch
13
+ import torch.nn as nn
14
+ import threading
15
+ import logging
16
+ import sqlite3
17
+ import dask.dataframe as dd
18
+
19
+ # Konfiguration des Loggers
20
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
21
+
22
+ # Globale Variable zur Überprüfung der Initialisierung
23
+ initialized = False
24
+ category_nodes = []
25
+ questions = []
26
+ model_saved = False # Schutzvariable
27
+
28
+ # Überprüfen, ob der Ordner existiert
29
+ output_dir = "plots"
30
+ if not os.path.exists(output_dir):
31
+ os.makedirs(output_dir)
32
+
33
+ def split_csv(filename, chunk_size=1000, output_dir="data"):
34
+ """
35
+ Teilt eine CSV-Datei in kleinere Chunks auf und speichert diese in einem angegebenen Verzeichnis.
36
+
37
+ Args:
38
+ filename (str): Der Pfad zur CSV-Datei.
39
+ chunk_size (int): Die Anzahl der Zeilen pro Chunk.
40
+ output_dir (str): Das Verzeichnis, in dem die Chunks gespeichert werden sollen.
41
+ """
42
+ if not os.path.exists(output_dir):
43
+ os.makedirs(output_dir)
44
+
45
+ chunk_iter = pd.read_csv(filename, chunksize=chunk_size)
46
+ for i, chunk in enumerate(chunk_iter):
47
+ chunk.to_csv(os.path.join(output_dir, f"data_part_{i}.csv"), index=False)
48
+ logging.info(f"Chunk {i} mit {len(chunk)} Zeilen gespeichert.")
49
+
50
+ def strengthen_question_connection(category_nodes, question, category):
51
+ """
52
+ Verstärkt die Verbindung zwischen einer Frage und einer Kategorie im Netzwerk.
53
+
54
+ Args:
55
+ category_nodes (list): Liste der Kategorie-Knoten.
56
+ question (str): Die Frage, deren Verbindung verstärkt werden soll.
57
+ category (str): Die Kategorie, zu der die Frage gehört.
58
+ """
59
+ category_node = next((node for node in category_nodes if node.label == category), None)
60
+ if category_node:
61
+ for conn in category_node.connections:
62
+ if conn.target_node.label == question:
63
+ old_weight = conn.weight
64
+ conn.weight += 0.1 # Verstärkung der Verbindung
65
+ conn.weight = np.clip(conn.weight, 0, 1.0)
66
+ logging.info(f"Verstärkte Verbindung für Frage '{question}' in Kategorie '{category}': {old_weight:.4f} -> {conn.weight:.4f}")
67
+
68
+ def enhanced_hebbian_learning(node, target_node, learning_rate=0.2, decay_factor=0.01):
69
+ """
70
+ Wendet eine erweiterte Hebb'sche Lernregel an, um die Verbindung zwischen zwei Knoten zu verstärken.
71
+
72
+ Args:
73
+ node (Node): Der Ursprungsknoten.
74
+ target_node (Node): Der Zielknoten.
75
+ learning_rate (float): Die Lernrate.
76
+ decay_factor (float): Der Verfallsfaktor.
77
+ """
78
+ old_weight = None
79
+ for conn in node.connections:
80
+ if conn.target_node == target_node:
81
+ old_weight = conn.weight
82
+ conn.weight += learning_rate * node.activation * target_node.activation
83
+ conn.weight = np.clip(conn.weight - decay_factor * conn.weight, 0, 1.0)
84
+ break
85
+
86
+ if old_weight is not None:
87
+ logging.info(f"Hebb'sches Lernen angewendet: Gewicht {old_weight:.4f} -> {conn.weight:.4f}")
88
+
89
+ def simulate_question_answering(category_nodes, question, questions):
90
+ """
91
+ Simuliert die Beantwortung einer Frage im Netzwerk.
92
+
93
+ Args:
94
+ category_nodes (list): Liste der Kategorie-Knoten.
95
+ question (str): Die Frage, die beantwortet werden soll.
96
+ questions (list): Liste aller Fragen.
97
+
98
+ Returns:
99
+ float: Die Aktivierung des Kategorie-Knotens.
100
+ """
101
+ category = next((q['category'] for q in questions if q['question'] == question), None)
102
+ if not category:
103
+ logging.warning(f"Frage '{question}' nicht gefunden!")
104
+ return None
105
+
106
+ category_node = next((node for node in category_nodes if node.label == category), None)
107
+ if category_node:
108
+ propagate_signal(category_node, input_signal=0.9, emotion_weights={}, emotional_state=1.0)
109
+ activation = category_node.activation
110
+ if activation is None or activation <= 0:
111
+ logging.warning(f"Kategorie '{category}' hat eine ungültige Aktivierung: {activation}")
112
+ return 0.0 # Rückgabe von 0, falls die Aktivierung fehlschlägt
113
+ logging.info(f"Verarbeite Frage: '{question}' → Kategorie: '{category}' mit Aktivierung {activation:.4f}")
114
+ return activation # Entfernte doppelte Logging-Ausgabe
115
+ else:
116
+ logging.warning(f"Kategorie '{category}' nicht im Netzwerk gefunden. Die Kategorie wird neu hinzugefügt!")
117
+ return 0.0
118
+
119
+ def find_question_by_keyword(questions, keyword):
120
+ """
121
+ Findet Fragen, die ein bestimmtes Schlüsselwort enthalten.
122
+
123
+ Args:
124
+ questions (list): Liste aller Fragen.
125
+ keyword (str): Das Schlüsselwort, nach dem gesucht werden soll.
126
+
127
+ Returns:
128
+ list: Liste der gefundenen Fragen.
129
+ """
130
+ matching_questions = [q for q in questions if keyword.lower() in q['question'].lower()]
131
+ return matching_questions if matching_questions else None
132
+
133
+ def find_similar_question(questions, query):
134
+ """
135
+ Findet die ähnlichste Frage basierend auf einfachen Ähnlichkeitsmetriken.
136
+
137
+ Args:
138
+ questions (list): Liste aller Fragen.
139
+ query (str): Die Abfrage, nach der gesucht werden soll.
140
+
141
+ Returns:
142
+ dict: Die ähnlichste Frage.
143
+ """
144
+ from difflib import get_close_matches
145
+ question_texts = [q['question'] for q in questions]
146
+ closest_matches = get_close_matches(query, question_texts, n=1, cutoff=0.6)
147
+
148
+ if closest_matches:
149
+ matched_question = next((q for q in questions if q['question'] == closest_matches[0]), None)
150
+ return matched_question
151
+ else:
152
+ return {"question": "Keine passende Frage gefunden", "category": "Unbekannt"}
153
+
154
+ def test_model(category_nodes, questions, query):
155
+ """
156
+ Testet das Modell mit einer Abfrage und gibt die gefundene Frage und die ähnlichste Frage aus.
157
+
158
+ Args:
159
+ category_nodes (list): Liste der Kategorie-Knoten.
160
+ questions (list): Liste aller Fragen.
161
+ query (str): Die Abfrage, nach der gesucht werden soll.
162
+ """
163
+ matched_question = find_question_by_keyword(questions, query)
164
+ if matched_question:
165
+ logging.info(f"Gefundene Frage: {matched_question[0]['question']} -> Kategorie: {matched_question[0]['category']}")
166
+ simulate_question_answering(category_nodes, matched_question[0]['question'], questions)
167
+ else:
168
+ logging.warning("Keine passende Frage gefunden.")
169
+
170
+ similarity_question = find_similar_question(questions, query)
171
+ logging.info(f"Ähnlichste Frage: {similarity_question['question']} -> Kategorie: {similarity_question['category']}")
172
+
173
+ def build_causal_graph(category_nodes):
174
+ """
175
+ Erstellt einen kausalen Graphen aus den Kategorie-Knoten.
176
+
177
+ Args:
178
+ category_nodes (list): Liste der Kategorie-Knoten.
179
+
180
+ Returns:
181
+ nx.DiGraph: Der erstellte kausale Graph.
182
+ """
183
+ G = nx.DiGraph()
184
+ for node in category_nodes:
185
+ G.add_node(node.label)
186
+ for conn in node.connections:
187
+ G.add_edge(node.label, conn.target_node.label, weight=conn.weight)
188
+ return G
189
+
190
+ def analyze_causality_multiple(G, num_pairs=3):
191
+ """
192
+ Analysiert kausale Pfade zwischen zufälligen Knotenpaaren im Graphen.
193
+
194
+ Args:
195
+ G (nx.DiGraph): Der kausale Graph.
196
+ num_pairs (int): Die Anzahl der zu analysierenden Knotenpaare.
197
+ """
198
+ if len(G.nodes) < 2:
199
+ logging.warning("Graph enthält nicht genügend Knoten für eine Analyse.")
200
+ return
201
+
202
+ for _ in range(num_pairs):
203
+ start_node, target_node = random.sample(G.nodes, 2)
204
+ logging.info(f"Analysiere kausale Pfade von '{start_node}' nach '{target_node}'")
205
+
206
+ try:
207
+ paths = list(nx.all_simple_paths(G, source=start_node, target=target_node))
208
+ if paths:
209
+ for path in paths:
210
+ logging.info(f"Kausaler Pfad: {' -> '.join(path)}")
211
+ else:
212
+ logging.info(f"Kein Pfad gefunden von '{start_node}' nach '{target_node}'")
213
+ except nx.NetworkXNoPath:
214
+ logging.warning(f"Kein direkter Pfad zwischen '{start_node}' und '{target_node}' gefunden.")
215
+
216
+ def analyze_node_influence(G):
217
+ """
218
+ Analysiert den Einfluss der Knoten im Graphen.
219
+
220
+ Args:
221
+ G (nx.DiGraph): Der kausale Graph.
222
+ """
223
+ influence_scores = nx.pagerank(G, alpha=0.85)
224
+ sorted_influences = sorted(influence_scores.items(), key=lambda x: x[1], reverse=True)
225
+ for node, score in sorted_influences:
226
+ logging.info(f"Knoten: {node}, Einfluss: {score:.4f}")
227
+
228
+ def do_intervention(node, new_value):
229
+ """
230
+ Führt eine Intervention auf einem Knoten durch, indem dessen Aktivierung auf einen neuen Wert gesetzt wird.
231
+
232
+ Args:
233
+ node (Node): Der Knoten, auf dem die Intervention durchgeführt werden soll.
234
+ new_value (float): Der neue Aktivierungswert.
235
+ """
236
+ logging.info(f"Intervention: Setze {node.label} auf {new_value}")
237
+ node.activation = new_value
238
+ for conn in node.connections:
239
+ conn.target_node.activation += node.activation * conn.weight
240
+
241
+ def contextual_causal_analysis(node, context_factors, learning_rate=0.1):
242
+ """
243
+ Verstärkt die kausale Beziehung eines Knotens basierend auf Kontextfaktoren.
244
+
245
+ Args:
246
+ node (Node): Der Knoten, dessen kausale Beziehung verstärkt werden soll.
247
+ context_factors (dict): Die Kontextfaktoren.
248
+ learning_rate (float): Die Lernrate.
249
+ """
250
+ context_factor = context_factors.get(node.label, 1.0)
251
+ if node.activation > 0.8 and context_factor > 1.0:
252
+ logging.info(f"Kausale Beziehung verstärkt für {node.label} aufgrund des Kontextes.")
253
+ for conn in node.connections:
254
+ conn.weight += learning_rate * context_factor
255
+ conn.weight = np.clip(conn.weight, 0, 1.0)
256
+ logging.info(f"Gewicht aktualisiert: {node.label} → {conn.target_node.label}, Gewicht: {conn.weight:.4f}")
257
+
258
+ class CausalInferenceNN(nn.Module):
259
+ """
260
+ Ein PyTorch-Modell für kausale Inferenz.
261
+ """
262
+ def __init__(self):
263
+ super(CausalInferenceNN, self).__init__()
264
+ self.fc1 = nn.Linear(10, 20)
265
+ self.fc2 = nn.Linear(20, 1)
266
+
267
+ def forward(self, x):
268
+ x = torch.relu(self.fc1(x))
269
+ return self.fc2(x)
270
+
271
+ def debug_connections(category_nodes):
272
+ """
273
+ Debuggt die Verbindungen zwischen den Kategorie-Knoten.
274
+
275
+ Args:
276
+ category_nodes (list): Liste der Kategorie-Knoten.
277
+ """
278
+ start_time = time.time()
279
+ for node in category_nodes:
280
+ logging.info(f"Knoten: {node.label}")
281
+ for conn in node.connections:
282
+ logging.info(f" Verbindung zu: {conn.target_node.label}, Gewicht: {conn.weight}")
283
+ end_time = time.time()
284
+ logging.info(f"debug_connections Ausführungszeit: {end_time - start_time:.4f} Sekunden")
285
+
286
+ def sigmoid(x):
287
+ """
288
+ Berechnet die Sigmoid-Funktion.
289
+
290
+ Args:
291
+ x (float): Der Eingabewert.
292
+
293
+ Returns:
294
+ float: Der Ausgabewert der Sigmoid-Funktion.
295
+ """
296
+ return 1 / (1 + np.exp(-x))
297
+
298
+ def add_activation_noise(activation, noise_level=0.1):
299
+ """
300
+ Fügt Rauschen zur Aktivierung hinzu.
301
+
302
+ Args:
303
+ activation (float): Die Aktivierung.
304
+ noise_level (float): Das Rausch-Level.
305
+
306
+ Returns:
307
+ float: Die Aktivierung mit Rauschen.
308
+ """
309
+ noise = np.random.normal(0, noise_level)
310
+ return np.clip(activation + noise, 0.0, 1.0)
311
+
312
+ def decay_weights(category_nodes, decay_rate=0.002, forgetting_curve=0.95):
313
+ """
314
+ Verfall der Gewichte der Verbindungen zwischen den Knoten.
315
+
316
+ Args:
317
+ category_nodes (list): Liste der Kategorie-Knoten.
318
+ decay_rate (float): Die Verfallsrate.
319
+ forgetting_curve (float): Die Vergessenskurve.
320
+ """
321
+ for node in category_nodes:
322
+ for conn in node.connections:
323
+ conn.weight *= (1 - decay_rate) * forgetting_curve
324
+
325
+ def reward_connections(category_nodes, target_category, reward_factor=0.1):
326
+ """
327
+ Belohnt die Verbindungen zu einer bestimmten Kategorie.
328
+
329
+ Args:
330
+ category_nodes (list): Liste der Kategorie-Knoten.
331
+ target_category (str): Die Zielkategorie.
332
+ reward_factor (float): Der Belohnungsfaktor.
333
+ """
334
+ for node in category_nodes:
335
+ if node.label == target_category:
336
+ for conn in node.connections:
337
+ conn.weight += reward_factor
338
+ conn.weight = np.clip(conn.weight, 0, 1.0)
339
+
340
+ def apply_emotion_weight(activation, category_label, emotion_weights, emotional_state=1.0):
341
+ """
342
+ Wendet ein emotionales Gewicht auf die Aktivierung an.
343
+
344
+ Args:
345
+ activation (float): Die Aktivierung.
346
+ category_label (str): Das Label der Kategorie.
347
+ emotion_weights (dict): Die emotionalen Gewichte.
348
+ emotional_state (float): Der emotionale Zustand.
349
+
350
+ Returns:
351
+ float: Die gewichtete Aktivierung.
352
+ """
353
+ emotion_factor = emotion_weights.get(category_label, 1.0) * emotional_state
354
+ return activation * emotion_factor
355
+
356
+ def generate_simulated_answers(data, personality_distributions):
357
+ """
358
+ Generiert simulierte Antworten basierend auf Persönlichkeitsverteilungen.
359
+
360
+ Args:
361
+ data (pd.DataFrame): Die Eingabedaten.
362
+ personality_distributions (dict): Die Persönlichkeitsverteilungen.
363
+
364
+ Returns:
365
+ list: Die simulierten Antworten.
366
+ """
367
+ simulated_answers = []
368
+ for _, row in data.iterrows():
369
+ category = row['Kategorie']
370
+ mean = personality_distributions.get(category, 0.5)
371
+ simulated_answer = np.clip(np.random.normal(mean, 0.2), 0.0, 1.0)
372
+ simulated_answers.append(simulated_answer)
373
+ return simulated_answers
374
+
375
+ def social_influence(category_nodes, social_network, influence_factor=0.1):
376
+ """
377
+ Wendet sozialen Einfluss auf die Verbindungen zwischen den Knoten an.
378
+
379
+ Args:
380
+ category_nodes (list): Liste der Kategorie-Knoten.
381
+ social_network (dict): Das soziale Netzwerk.
382
+ influence_factor (float): Der Einflussfaktor.
383
+ """
384
+ for node in category_nodes:
385
+ for conn in node.connections:
386
+ social_impact = sum([social_network.get(conn.target_node.label, 0)]) * influence_factor
387
+ conn.weight += social_impact
388
+ conn.weight = np.clip(conn.weight, 0, 1.0)
389
+
390
+ def update_emotional_state(emotional_state, emotional_change_rate=0.02):
391
+ """
392
+ Aktualisiert den emotionalen Zustand.
393
+
394
+ Args:
395
+ emotional_state (float): Der emotionale Zustand.
396
+ emotional_change_rate (float): Die Änderungsrate des emotionalen Zustands.
397
+
398
+ Returns:
399
+ float: Der aktualisierte emotionale Zustand.
400
+ """
401
+ emotional_state += np.random.normal(0, emotional_change_rate)
402
+ return np.clip(emotional_state, 0.7, 1.5)
403
+
404
+ def apply_contextual_factors(activation, node, context_factors):
405
+ """
406
+ Wendet kontextuelle Faktoren auf die Aktivierung an.
407
+
408
+ Args:
409
+ activation (float): Die Aktivierung.
410
+ node (Node): Der Knoten.
411
+ context_factors (dict): Die kontextuellen Faktoren.
412
+
413
+ Returns:
414
+ float: Die aktualisierte Aktivierung.
415
+ """
416
+ context_factor = context_factors.get(node.label, 1.0)
417
+ return activation * context_factor * random.uniform(0.9, 1.1)
418
+
419
+ def long_term_memory(category_nodes, long_term_factor=0.01):
420
+ """
421
+ Verstärkt die Gewichte der Verbindungen im Langzeitgedächtnis.
422
+
423
+ Args:
424
+ category_nodes (list): Liste der Kategorie-Knoten.
425
+ long_term_factor (float): Der Langzeitfaktor.
426
+ """
427
+ for node in category_nodes:
428
+ for conn in node.connections:
429
+ conn.weight += long_term_factor * conn.weight
430
+ conn.weight = np.clip(conn.weight, 0, 1.0)
431
+
432
+ def hebbian_learning(node, learning_rate=0.3, weight_limit=1.0, reg_factor=0.005):
433
+ """
434
+ Wendet Hebb'sches Lernen auf die Verbindungen eines Knotens an.
435
+
436
+ Args:
437
+ node (Node): Der Knoten.
438
+ learning_rate (float): Die Lernrate.
439
+ weight_limit (float): Die Gewichtsgrenze.
440
+ reg_factor (float): Der Regularisierungsfaktor.
441
+ """
442
+ for connection in node.connections:
443
+ old_weight = connection.weight
444
+ connection.weight += learning_rate * node.activation * connection.target_node.activation
445
+ connection.weight = np.clip(connection.weight, -weight_limit, weight_limit)
446
+ connection.weight -= reg_factor * connection.weight
447
+ node.activation_history.append(node.activation) # Aktivierung speichern
448
+ connection.target_node.activation_history.append(connection.target_node.activation)
449
+ logging.info(f"Hebb'sches Lernen: Gewicht von {old_weight:.4f} auf {connection.weight:.4f} erhöht")
450
+
451
+ class Connection:
452
+ """
453
+ Eine Verbindung zwischen zwei Knoten im Netzwerk.
454
+ """
455
+ def __init__(self, target_node, weight=None):
456
+ self.target_node = target_node
457
+ self.weight = weight if weight is not None else random.uniform(0.1, 1.0)
458
+
459
+ class Node:
460
+ """
461
+ Ein Knoten im Netzwerk.
462
+ """
463
+ def __init__(self, label):
464
+ self.label = label
465
+ self.connections = []
466
+ self.activation = 0.0
467
+ self.activation_history = []
468
+
469
+ def add_connection(self, target_node, weight=None):
470
+ """
471
+ Fügt eine Verbindung zu einem Zielknoten hinzu.
472
+
473
+ Args:
474
+ target_node (Node): Der Zielknoten.
475
+ weight (float): Das Gewicht der Verbindung.
476
+ """
477
+ self.connections.append(Connection(target_node, weight))
478
+
479
+ def save_state(self):
480
+ """
481
+ Speichert den Zustand des Knotens.
482
+
483
+ Returns:
484
+ dict: Der gespeicherte Zustand des Knotens.
485
+ """
486
+ return {
487
+ "label": self.label,
488
+ "activation": self.activation,
489
+ "activation_history": self.activation_history,
490
+ "connections": [{"target": conn.target_node.label, "weight": conn.weight} for conn in self.connections]
491
+ }
492
+
493
+ @staticmethod
494
+ def load_state(state, nodes_dict):
495
+ """
496
+ Lädt den Zustand eines Knotens.
497
+
498
+ Args:
499
+ state (dict): Der gespeicherte Zustand des Knotens.
500
+ nodes_dict (dict): Ein Dictionary der Knoten.
501
+
502
+ Returns:
503
+ Node: Der geladene Knoten.
504
+ """
505
+ node = Node(state["label"])
506
+ node.activation = state["activation"]
507
+ node.activation_history = state["activation_history"]
508
+ for conn_state in state["connections"]:
509
+ target_node = nodes_dict[conn_state["target"]]
510
+ connection = Connection(target_node, conn_state["weight"])
511
+ node.connections.append(connection)
512
+ return node
513
+
514
+ class MemoryNode(Node):
515
+ """
516
+ Ein Gedächtnisknoten im Netzwerk.
517
+ """
518
+ def __init__(self, label, memory_type="short_term"):
519
+ super().__init__(label)
520
+ self.memory_type = memory_type
521
+ self.retention_time = {"short_term": 5, "mid_term": 20, "long_term": 100}[memory_type]
522
+ self.time_in_memory = 0
523
+
524
+ def decay(self, decay_rate, context_factors, emotional_state):
525
+ """
526
+ Verfall der Gewichte der Verbindungen basierend auf dem Gedächtnistyp.
527
+
528
+ Args:
529
+ decay_rate (float): Die Verfallsrate.
530
+ context_factors (dict): Die kontextuellen Faktoren.
531
+ emotional_state (float): Der emotionale Zustand.
532
+ """
533
+ context_factor = context_factors.get(self.label, 1.0)
534
+ emotional_factor = emotional_state
535
+ for conn in self.connections:
536
+ if self.memory_type == "short_term":
537
+ conn.weight *= (1 - decay_rate * 2 * context_factor * emotional_factor)
538
+ elif self.memory_type == "mid_term":
539
+ conn.weight *= (1 - decay_rate * context_factor * emotional_factor)
540
+ elif self.memory_type == "long_term":
541
+ conn.weight *= (1 - decay_rate * 0.5 * context_factor * emotional_factor)
542
+
543
+ def promote(self, activation_threshold=0.7):
544
+ """
545
+ Fördert den Knoten basierend auf der Aktivierungshistorie.
546
+
547
+ Args:
548
+ activation_threshold (float): Der Aktivierungsschwellenwert.
549
+ """
550
+ if len(self.activation_history) == 0:
551
+ return
552
+ if self.memory_type == "short_term" and np.mean(self.activation_history[-5:]) > activation_threshold:
553
+ self.memory_type = "mid_term"
554
+ self.retention_time = 20
555
+ elif self.memory_type == "mid_term" and np.mean(self.activation_history[-20:]) > activation_threshold:
556
+ self.memory_type = "long_term"
557
+ self.retention_time = 100
558
+
559
+ class CortexCreativus(Node):
560
+ """
561
+ Ein Knoten, der neue Ideen generiert.
562
+ """
563
+ def __init__(self, label):
564
+ super().__init__(label)
565
+
566
+ def generate_new_ideas(self, category_nodes):
567
+ """
568
+ Generiert neue Ideen basierend auf den Aktivierungen der Kategorie-Knoten.
569
+
570
+ Args:
571
+ category_nodes (list): Liste der Kategorie-Knoten.
572
+
573
+ Returns:
574
+ list: Die generierten neuen Ideen.
575
+ """
576
+ new_ideas = []
577
+ for node in category_nodes:
578
+ if node.activation > 0.5:
579
+ new_idea = f"New idea based on {node.label} with activation {node.activation}"
580
+ new_ideas.append(new_idea)
581
+ return new_ideas
582
+
583
+ class SimulatrixNeuralis(Node):
584
+ """
585
+ Ein Knoten, der Szenarien simuliert.
586
+ """
587
+ def __init__(self, label):
588
+ super().__init__(label)
589
+
590
+ def simulate_scenarios(self, category_nodes):
591
+ """
592
+ Simuliert Szenarien basierend auf den Aktivierungen der Kategorie-Knoten.
593
+
594
+ Args:
595
+ category_nodes (list): Liste der Kategorie-Knoten.
596
+
597
+ Returns:
598
+ list: Die simulierten Szenarien.
599
+ """
600
+ scenarios = []
601
+ for node in category_nodes:
602
+ if node.activation > 0.5:
603
+ scenario = f"Simulated scenario based on {node.label} with activation {node.activation}"
604
+ scenarios.append(scenario)
605
+ return scenarios
606
+
607
+ class CortexCriticus(Node):
608
+ """
609
+ Ein Knoten, der Ideen bewertet.
610
+ """
611
+ def __init__(self, label):
612
+ super().__init__(label)
613
+
614
+ def evaluate_ideas(self, ideas):
615
+ """
616
+ Bewertet Ideen.
617
+
618
+ Args:
619
+ ideas (list): Die zu bewertenden Ideen.
620
+
621
+ Returns:
622
+ list: Die bewerteten Ideen.
623
+ """
624
+ evaluated_ideas = []
625
+ for idea in ideas:
626
+ evaluation_score = random.uniform(0, 1)
627
+ evaluation = f"Evaluated idea: {idea} - Score: {evaluation_score}"
628
+ evaluated_ideas.append(evaluation)
629
+ return evaluated_ideas
630
+
631
+ class LimbusAffectus(Node):
632
+ """
633
+ Ein Knoten, der emotionale Gewichte auf Ideen anwendet.
634
+ """
635
+ def __init__(self, label):
636
+ super().__init__(label)
637
+
638
+ def apply_emotion_weight(self, ideas, emotional_state):
639
+ """
640
+ Wendet emotionale Gewichte auf Ideen an.
641
+
642
+ Args:
643
+ ideas (list): Die Ideen.
644
+ emotional_state (float): Der emotionale Zustand.
645
+
646
+ Returns:
647
+ list: Die emotional gewichteten Ideen.
648
+ """
649
+ weighted_ideas = []
650
+ for idea in ideas:
651
+ weighted_idea = f"Emotionally weighted idea: {idea} - Weight: {emotional_state}"
652
+ weighted_ideas.append(weighted_idea)
653
+ return weighted_ideas
654
+
655
+ class MetaCognitio(Node):
656
+ """
657
+ Ein Knoten, der das System optimiert.
658
+ """
659
+ def __init__(self, label):
660
+ super().__init__(label)
661
+
662
+ def optimize_system(self, category_nodes):
663
+ """
664
+ Optimiert das System.
665
+
666
+ Args:
667
+ category_nodes (list): Liste der Kategorie-Knoten.
668
+ """
669
+ for node in category_nodes:
670
+ node.activation *= random.uniform(0.9, 1.1)
671
+
672
+ class CortexSocialis(Node):
673
+ """
674
+ Ein Knoten, der soziale Interaktionen simuliert.
675
+ """
676
+ def __init__(self, label):
677
+ super().__init__(label)
678
+
679
+ def simulate_social_interactions(self, category_nodes):
680
+ """
681
+ Simuliert soziale Interaktionen basierend auf den Aktivierungen der Kategorie-Knoten.
682
+
683
+ Args:
684
+ category_nodes (list): Liste der Kategorie-Knoten.
685
+
686
+ Returns:
687
+ list: Die simulierten sozialen Interaktionen.
688
+ """
689
+ interactions = []
690
+ for node in category_nodes:
691
+ if node.activation > 0.5:
692
+ interaction = f"Simulated social interaction based on {node.label} with activation {node.activation}"
693
+ interactions.append(interaction)
694
+ return interactions
695
+
696
+ def connect_new_brains_to_network(category_nodes, new_brains):
697
+ """
698
+ Verbindet neue Gehirne mit dem Netzwerk.
699
+
700
+ Args:
701
+ category_nodes (list): Liste der Kategorie-Knoten.
702
+ new_brains (list): Liste der neuen Gehirne.
703
+ """
704
+ for brain in new_brains:
705
+ for node in category_nodes:
706
+ brain.add_connection(node)
707
+ node.add_connection(brain)
708
+
709
+ def initialize_quiz_network(categories):
710
+ """
711
+ Initialisiert das Quiz-Netzwerk mit den gegebenen Kategorien.
712
+
713
+ Args:
714
+ categories (list): Liste der Kategorien.
715
+
716
+ Returns:
717
+ list: Liste der Kategorie-Knoten.
718
+ """
719
+ try:
720
+ category_nodes = [Node(c) for c in categories]
721
+ for node in category_nodes:
722
+ for target_node in category_nodes:
723
+ if node != target_node:
724
+ node.add_connection(target_node)
725
+ logging.debug(f"Verbindung hinzugefügt: {node.label} → {target_node.label}")
726
+ debug_connections(category_nodes)
727
+ for node in category_nodes:
728
+ logging.info(f"Knoten erstellt: {node.label}")
729
+ for conn in node.connections:
730
+ logging.info(f" → Verbindung zu {conn.target_node.label} mit Gewicht {conn.weight:.4f}")
731
+ return category_nodes
732
+ except Exception as e:
733
+ logging.error(f"Fehler bei der Netzwerk-Initialisierung: {e}")
734
+ return []
735
+
736
+ def propagate_signal(node, input_signal, emotion_weights, emotional_state=1.0, context_factors=None):
737
+ """
738
+ Propagiert ein Signal durch das Netzwerk.
739
+
740
+ Args:
741
+ node (Node): Der Knoten, an dem das Signal beginnt.
742
+ input_signal (float): Das Eingangssignal.
743
+ emotion_weights (dict): Die emotionalen Gewichte.
744
+ emotional_state (float): Der emotionale Zustand.
745
+ context_factors (dict): Die kontextuellen Faktoren.
746
+ """
747
+ node.activation = add_activation_noise(sigmoid(input_signal * random.uniform(0.8, 1.2)))
748
+ node.activation_history.append(node.activation) # Aktivierung speichern
749
+ node.activation = apply_emotion_weight(node.activation, node.label, emotion_weights, emotional_state)
750
+ if context_factors:
751
+ node.activation = apply_contextual_factors(node.activation, node, context_factors)
752
+ logging.info(f"Signalpropagation für {node.label}: Eingangssignal {input_signal:.4f}")
753
+ for connection in node.connections:
754
+ logging.info(f" → Signal an {connection.target_node.label} mit Gewicht {connection.weight:.4f}")
755
+ connection.target_node.activation += node.activation * connection.weight
756
+
757
+ def propagate_signal_with_memory(node, input_signal, category_nodes, memory_nodes, context_factors, emotional_state):
758
+ """
759
+ Propagiert ein Signal durch das Netzwerk mit Gedächtnis.
760
+
761
+ Args:
762
+ node (Node): Der Knoten, an dem das Signal beginnt.
763
+ input_signal (float): Das Eingangssignal.
764
+ category_nodes (list): Liste der Kategorie-Knoten.
765
+ memory_nodes (list): Liste der Gedächtnisknoten.
766
+ context_factors (dict): Die kontextuellen Faktoren.
767
+ emotional_state (float): Der emotionale Zustand.
768
+ """
769
+ node.activation = add_activation_noise(sigmoid(input_signal))
770
+ node.activation_history.append(node.activation)
771
+ for connection in node.connections:
772
+ connection.target_node.activation += node.activation * connection.weight
773
+ for memory_node in memory_nodes:
774
+ memory_node.time_in_memory += 1
775
+ memory_node.promote()
776
+
777
+ def simulate_learning(data, category_nodes, personality_distributions, epochs=1, learning_rate=0.8, reward_interval=5, decay_rate=0.002, emotional_state=1.0, context_factors=None):
778
+ """
779
+ Simuliert das Lernen im Netzwerk.
780
+
781
+ Args:
782
+ data (pd.DataFrame): Die Eingabedaten.
783
+ category_nodes (list): Liste der Kategorie-Knoten.
784
+ personality_distributions (dict): Die Persönlichkeitsverteilungen.
785
+ epochs (int): Die Anzahl der Epochen.
786
+ learning_rate (float): Die Lernrate.
787
+ reward_interval (int): Das Belohnungsintervall.
788
+ decay_rate (float): Die Verfallsrate.
789
+ emotional_state (float): Der emotionale Zustand.
790
+ context_factors (dict): Die kontextuellen Faktoren.
791
+
792
+ Returns:
793
+ tuple: Die Aktivierungshistorie und die Gewichtshistorie.
794
+ """
795
+ if context_factors is None:
796
+ context_factors = {}
797
+
798
+ weights_history = {f"{node.label} → {conn.target_node.label}": [] for node in category_nodes for conn in node.connections}
799
+ activation_history = {node.label: [] for node in category_nodes}
800
+ question_nodes = []
801
+
802
+ for idx, row in data.iterrows():
803
+ q_node = Node(row['Frage'])
804
+ question_nodes.append(q_node)
805
+ category_label = row['Kategorie'].strip()
806
+ category_node = next((c for c in category_nodes if c.label == category_label), None)
807
+ if category_node:
808
+ q_node.add_connection(category_node)
809
+ logging.debug(f"Verbindung hinzugefügt: {q_node.label} → {category_node.label}")
810
+ else:
811
+ logging.warning(f"Warnung: Kategorie '{category_label}' nicht gefunden für Frage '{row['Frage']}'.")
812
+
813
+ emotion_weights = {category: 1.0 for category in data['Kategorie'].unique()}
814
+ social_network = {category: random.uniform(0.1, 1.0) for category in data['Kategorie'].unique()}
815
+
816
+ for epoch in range(epochs):
817
+ logging.info(f"\n--- Epoche {epoch + 1} ---")
818
+ simulated_answers = generate_simulated_answers(data, personality_distributions)
819
+
820
+ for node in category_nodes:
821
+ node.activation_sum = 0.0
822
+ node.activation_count = 0
823
+
824
+ for node in category_nodes:
825
+ propagate_signal(node, random.uniform(0.1, 0.9), emotion_weights, emotional_state, context_factors)
826
+ node.activation_history.append(node.activation) # Aktivierung speichern
827
+
828
+ for idx, q_node in enumerate(question_nodes):
829
+ for node in category_nodes + question_nodes:
830
+ node.activation = 0.0
831
+ answer = simulated_answers[idx]
832
+ propagate_signal(q_node, answer, emotion_weights, emotional_state, context_factors)
833
+ q_node.activation_history.append(q_node.activation) # Aktivierung speichern
834
+ hebbian_learning(q_node, learning_rate)
835
+
836
+ for node in category_nodes:
837
+ node.activation_sum += node.activation
838
+ if node.activation > 0:
839
+ node.activation_count += 1
840
+
841
+ for node in category_nodes:
842
+ for conn in node.connections:
843
+ weights_history[f"{node.label} → {conn.target_node.label}"].append(conn.weight)
844
+ logging.debug(f"Gewicht aktualisiert: {node.label} → {conn.target_node.label}, Gewicht: {conn.weight}")
845
+
846
+ # Kausalitätsverstärkung anwenden
847
+ contextual_causal_analysis(q_node, context_factors, learning_rate)
848
+
849
+ for node in category_nodes:
850
+ if node.activation_count > 0:
851
+ mean_activation = node.activation_sum / node.activation_count
852
+ activation_history[node.label].append(mean_activation)
853
+ logging.info(f"Durchschnittliche Aktivierung für Knoten {node.label}: {mean_activation:.4f}")
854
+ else:
855
+ activation_history[node.label].append(0.0)
856
+ logging.info(f"Knoten {node.label} wurde in dieser Epoche nicht aktiviert.")
857
+
858
+ if (epoch + 1) % reward_interval == 0:
859
+ target_category = random.choice(data['Kategorie'].unique())
860
+ reward_connections(category_nodes, target_category=target_category)
861
+
862
+ decay_weights(category_nodes, decay_rate=decay_rate)
863
+ social_influence(category_nodes, social_network)
864
+
865
+ logging.info("Simulation abgeschlossen. Ergebnisse werden analysiert...")
866
+ return activation_history, weights_history
867
+
868
+ def simulate_multilevel_memory(data, category_nodes, personality_distributions, epochs=1):
869
+ """
870
+ Simuliert das Lernen im Netzwerk mit mehrstufigem Gedächtnis.
871
+
872
+ Args:
873
+ data (pd.DataFrame): Die Eingabedaten.
874
+ category_nodes (list): Liste der Kategorie-Knoten.
875
+ personality_distributions (dict): Die Persönlichkeitsverteilungen.
876
+ epochs (int): Die Anzahl der Epochen.
877
+
878
+ Returns:
879
+ tuple: Die Kurzzeit-, Mittelzeit- und Langzeitgedächtnisknoten.
880
+ """
881
+ short_term_memory = [MemoryNode(c, "short_term") for c in category_nodes]
882
+ mid_term_memory = []
883
+ long_term_memory = []
884
+ memory_nodes = short_term_memory + mid_term_memory + long_term_memory
885
+ context_factors = {question: random.uniform(0.9, 1.1) for question in data['Frage'].unique()}
886
+ emotional_state = 1.0
887
+ for epoch in range(epochs):
888
+ logging.info(f"\n--- Epoche {epoch + 1} ---")
889
+ for node in short_term_memory:
890
+ input_signal = random.uniform(0.1, 1.0)
891
+ propagate_signal_with_memory(node, input_signal, category_nodes, memory_nodes, context_factors, emotional_state)
892
+ for memory_node in memory_nodes:
893
+ memory_node.decay(decay_rate=0.01, context_factors=context_factors, emotional_state=emotional_state)
894
+ for memory_node in memory_nodes:
895
+ memory_node.promote()
896
+ short_term_memory, mid_term_memory, long_term_memory = update_memory_stages(memory_nodes)
897
+ logging.info(f"Epoche {epoch + 1}: Kurzzeit {len(short_term_memory)}, Mittelzeit {len(mid_term_memory)}, Langzeit {len(long_term_memory)}")
898
+ return short_term_memory, mid_term_memory, long_term_memory
899
+
900
+ def update_memory_stages(memory_nodes):
901
+ """
902
+ Aktualisiert die Gedächtnisstufen der Gedächtnisknoten.
903
+
904
+ Args:
905
+ memory_nodes (list): Liste der Gedächtnisknoten.
906
+
907
+ Returns:
908
+ tuple: Die Kurzzeit-, Mittelzeit- und Langzeitgedächtnisknoten.
909
+ """
910
+ short_term_memory = [node for node in memory_nodes if node.memory_type == "short_term"]
911
+ mid_term_memory = [node for node in memory_nodes if node.memory_type == "mid_term"]
912
+ long_term_memory = [node for node in memory_nodes if node.memory_type == "long_term"]
913
+ return short_term_memory, mid_term_memory, long_term_memory
914
+
915
+ def plot_activation_history(activation_history, filename="activation_history.png"):
916
+ """
917
+ Erstellt einen Plot der Aktivierungshistorie.
918
+
919
+ Args:
920
+ activation_history (dict): Die Aktivierungshistorie.
921
+ filename (str): Der Dateiname des Plots.
922
+ """
923
+ if not activation_history:
924
+ logging.warning("No activation history to plot")
925
+ return
926
+ plt.figure(figsize=(12, 8))
927
+ for label, activations in activation_history.items():
928
+ if len(activations) > 0:
929
+ plt.plot(range(1, len(activations) + 1), activations, label=label)
930
+ plt.title("Entwicklung der Aktivierungen während des Lernens")
931
+ plt.xlabel("Epoche")
932
+ plt.ylabel("Aktivierung")
933
+ plt.legend()
934
+ plt.grid(True)
935
+ plt.savefig(os.path.join(output_dir, filename), dpi=300, bbox_inches="tight")
936
+ plt.close()
937
+ logging.info(f"Plot gespeichert unter: {os.path.join(output_dir, filename)}")
938
+
939
+ def plot_dynamics(activation_history, weights_history, filename="dynamics.png"):
940
+ """
941
+ Erstellt einen Plot der Aktivierungs- und Gewichtsdynamik.
942
+
943
+ Args:
944
+ activation_history (dict): Die Aktivierungshistorie.
945
+ weights_history (dict): Die Gewichtshistorie.
946
+ filename (str): Der Dateiname des Plots.
947
+ """
948
+ if not weights_history:
949
+ logging.error("weights_history ist leer.")
950
+ return
951
+
952
+ plt.figure(figsize=(16, 12))
953
+ plt.subplot(2, 2, 1)
954
+ for label, activations in activation_history.items():
955
+ if len(activations) > 0:
956
+ plt.plot(range(1, len(activations) + 1), activations, label=label)
957
+ plt.title("Entwicklung der Aktivierungen während des Lernens")
958
+ plt.xlabel("Epoche")
959
+ plt.ylabel("Aktivierung")
960
+ plt.legend()
961
+ plt.grid(True)
962
+
963
+ plt.subplot(2, 2, 2)
964
+ for label, weights in weights_history.items():
965
+ if len(weights) > 0:
966
+ plt.plot(range(1, len(weights) + 1), weights, label=label, alpha=0.7)
967
+ plt.title("Entwicklung der Verbindungsgewichte während des Lernens")
968
+ plt.xlabel("Epoche")
969
+ plt.ylabel("Gewicht")
970
+ plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
971
+ plt.grid(True)
972
+
973
+ plt.savefig(os.path.join(output_dir, filename), dpi=300, bbox_inches="tight")
974
+ plt.close()
975
+ logging.info(f"Plot gespeichert unter: {os.path.join(output_dir, filename)}")
976
+
977
+ def plot_memory_distribution(short_term_memory, mid_term_memory, long_term_memory, filename="memory_distribution.png"):
978
+ """
979
+ Erstellt einen Plot der Gedächtnisverteilung.
980
+
981
+ Args:
982
+ short_term_memory (list): Liste der Kurzzeitgedächtnisknoten.
983
+ mid_term_memory (list): Liste der Mittelzeitgedächtnisknoten.
984
+ long_term_memory (list): Liste der Langzeitgedächtnisknoten.
985
+ filename (str): Der Dateiname des Plots.
986
+ """
987
+ counts = [len(short_term_memory), len(mid_term_memory), len(long_term_memory)]
988
+ labels = ["Kurzfristig", "Mittelfristig", "Langfristig"]
989
+ plt.figure(figsize=(8, 6))
990
+ plt.bar(labels, counts, color=["red", "blue", "green"])
991
+ plt.title("Verteilung der Gedächtnisknoten")
992
+ plt.ylabel("Anzahl der Knoten")
993
+ plt.savefig(os.path.join(output_dir, filename), dpi=300, bbox_inches="tight")
994
+ plt.close()
995
+ logging.info(f"Plot gespeichert unter: {os.path.join(output_dir, filename)}")
996
+
997
+ def plot_activation_heatmap(activation_history, filename="activation_heatmap.png"):
998
+ """
999
+ Erstellt einen Plot der Aktivierungswerte als Heatmap.
1000
+
1001
+ Args:
1002
+ activation_history (dict): Die Aktivierungshistorie.
1003
+ filename (str): Der Dateiname des Plots.
1004
+ """
1005
+ if not activation_history:
1006
+ logging.warning("No activation history to plot")
1007
+ return
1008
+
1009
+ min_length = min(len(activations) for activations in activation_history.values())
1010
+ truncated_activations = {key: values[:min_length] for key, values in activation_history.items()}
1011
+
1012
+ plt.figure(figsize=(12, 8))
1013
+ heatmap_data = np.array([activations for activations in truncated_activations.values()])
1014
+
1015
+ if heatmap_data.size == 0:
1016
+ logging.error("Heatmap-Daten sind leer. Überprüfen Sie die Aktivierungshistorie.")
1017
+ return
1018
+
1019
+ sns.heatmap(heatmap_data, cmap="YlGnBu", xticklabels=truncated_activations.keys(), yticklabels=False)
1020
+ plt.title("Heatmap der Aktivierungswerte")
1021
+ plt.xlabel("Kategorie")
1022
+ plt.ylabel("Epoche")
1023
+ plt.savefig(os.path.join(output_dir, filename), dpi=300, bbox_inches="tight")
1024
+ plt.close()
1025
+ logging.info(f"Plot gespeichert unter: {os.path.join(output_dir, filename)}")
1026
+
1027
+ def plot_network_topology(category_nodes, new_brains, filename="network_topology.png"):
1028
+ """
1029
+ Erstellt einen Plot der Netzwerktopologie.
1030
+
1031
+ Args:
1032
+ category_nodes (list): Liste der Kategorie-Knoten.
1033
+ new_brains (list): Liste der neuen Gehirne.
1034
+ filename (str): Der Dateiname des Plots.
1035
+ """
1036
+ G = nx.DiGraph()
1037
+ for node in category_nodes:
1038
+ G.add_node(node.label)
1039
+ for conn in node.connections:
1040
+ G.add_edge(node.label, conn.target_node.label, weight=conn.weight)
1041
+ for brain in new_brains:
1042
+ G.add_node(brain.label, color='red')
1043
+ for conn in brain.connections:
1044
+ G.add_edge(brain.label, conn.target_node.label, weight=conn.weight)
1045
+
1046
+ pos = nx.spring_layout(G)
1047
+ edge_labels = {(u, v): d['weight'] for u, v, d in G.edges(data=True)}
1048
+ node_colors = [G.nodes[node].get('color', 'skyblue') for node in G.nodes()]
1049
+
1050
+ nx.draw(G, pos, with_labels=True, node_size=3000, node_color=node_colors, font_size=10, font_weight="bold", edge_color="gray")
1051
+ nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels)
1052
+ plt.title("Netzwerktopologie")
1053
+ plt.savefig(os.path.join(output_dir, filename), dpi=300, bbox_inches="tight")
1054
+ plt.close()
1055
+ logging.info(f"Plot gespeichert unter: {os.path.join(output_dir, filename)}")
1056
+
1057
+ def save_model(category_nodes, filename="model.json"):
1058
+ """
1059
+ Speichert das Modell in einer JSON-Datei.
1060
+
1061
+ Args:
1062
+ category_nodes (list): Liste der Kategorie-Knoten.
1063
+ filename (str): Der Dateiname der JSON-Datei.
1064
+ """
1065
+ model_data = {
1066
+ "nodes": [node.save_state() for node in category_nodes]
1067
+ }
1068
+ with open(filename, "w") as file:
1069
+ json.dump(model_data, file, indent=4)
1070
+ logging.info(f"Modell gespeichert in {filename}")
1071
+
1072
+ def save_model_with_questions_and_answers(category_nodes, questions, filename="model_with_qa.json"):
1073
+ """
1074
+ Speichert das Modell mit Fragen und Antworten in einer JSON-Datei.
1075
+
1076
+ Args:
1077
+ category_nodes (list): Liste der Kategorie-Knoten.
1078
+ questions (list): Liste der Fragen.
1079
+ filename (str): Der Dateiname der JSON-Datei.
1080
+ """
1081
+ global model_saved
1082
+ logging.info("Starte Speichern des Modells...")
1083
+
1084
+ # Überprüfen, ob Änderungen vorgenommen wurden
1085
+ current_model_data = {
1086
+ "nodes": [node.save_state() for node in category_nodes],
1087
+ "questions": questions
1088
+ }
1089
+
1090
+ if os.path.exists(filename):
1091
+ try:
1092
+ with open(filename, "r", encoding="utf-8") as file:
1093
+ existing_model_data = json.load(file)
1094
+ if existing_model_data == current_model_data:
1095
+ logging.info("Keine Änderungen erkannt, erneutes Speichern übersprungen.")
1096
+ return
1097
+ except Exception as e:
1098
+ logging.warning(f"Fehler beim Überprüfen des vorhandenen Modells: {e}")
1099
+
1100
+ # Speichern des aktualisierten Modells
1101
+ try:
1102
+ with open(filename, "w", encoding="utf-8") as file:
1103
+ json.dump(current_model_data, file, indent=4)
1104
+ logging.info(f"Modell erfolgreich gespeichert unter {filename}.")
1105
+ model_saved = True # Setze auf True nach erfolgreichem Speichern
1106
+ except Exception as e:
1107
+ logging.error(f"Fehler beim Speichern des Modells: {e}")
1108
+
1109
+ def load_model_with_questions_and_answers(filename="model_with_qa.json"):
1110
+ """
1111
+ Lädt das Modell mit Fragen und Antworten aus einer JSON-Datei.
1112
+
1113
+ Args:
1114
+ filename (str): Der Dateiname der JSON-Datei.
1115
+
1116
+ Returns:
1117
+ tuple: Die Liste der Kategorie-Knoten und die Liste der Fragen.
1118
+ """
1119
+ global initialized
1120
+ if initialized:
1121
+ logging.info("Modell bereits initialisiert.")
1122
+ return None, None
1123
+
1124
+ if not os.path.exists(filename):
1125
+ logging.warning(f"Datei {filename} nicht gefunden. Netzwerk wird initialisiert.")
1126
+ return None, None
1127
+
1128
+ try:
1129
+ with open(filename, "r", encoding="utf-8") as file:
1130
+ model_data = json.load(file)
1131
+
1132
+ nodes_dict = {node_data["label"]: Node(node_data["label"]) for node_data in model_data["nodes"]}
1133
+
1134
+ for node_data in model_data["nodes"]:
1135
+ node = nodes_dict[node_data["label"]]
1136
+ node.activation = node_data.get("activation", 0.0)
1137
+ for conn_state in node_data["connections"]:
1138
+ target_node = nodes_dict.get(conn_state["target"])
1139
+ if target_node:
1140
+ node.add_connection(target_node, conn_state["weight"])
1141
+
1142
+ questions = model_data.get("questions", [])
1143
+ logging.info(f"Modell geladen mit {len(nodes_dict)} Knoten und {len(questions)} Fragen")
1144
+ initialized = True
1145
+ return list(nodes_dict.values()), questions
1146
+
1147
+ except json.JSONDecodeError as e:
1148
+ logging.error(f"Fehler beim Parsen der JSON-Datei: {e}")
1149
+ return None, None
1150
+
1151
+ def update_questions_with_answers(filename="model_with_qa.json"):
1152
+ """
1153
+ Aktualisiert die Fragen mit Antworten in der JSON-Datei.
1154
+
1155
+ Args:
1156
+ filename (str): Der Dateiname der JSON-Datei.
1157
+ """
1158
+ with open(filename, "r") as file:
1159
+ model_data = json.load(file)
1160
+
1161
+ for question in model_data["questions"]:
1162
+ if "answer" not in question:
1163
+ question["answer"] = input(f"Gib die Antwort für: '{question['question']}': ")
1164
+
1165
+ with open(filename, "w") as file:
1166
+ json.dump(model_data, file, indent=4)
1167
+ logging.info(f"Fragen wurden mit Antworten aktualisiert und gespeichert in {filename}")
1168
+
1169
+ def find_best_answer(category_nodes, questions, query):
1170
+ """
1171
+ Findet die beste Antwort auf eine Abfrage.
1172
+
1173
+ Args:
1174
+ category_nodes (list): Liste der Kategorie-Knoten.
1175
+ questions (list): Liste der Fragen.
1176
+ query (str): Die Abfrage.
1177
+
1178
+ Returns:
1179
+ str: Die beste Antwort.
1180
+ """
1181
+ matched_question = find_similar_question(questions, query)
1182
+ if matched_question:
1183
+ logging.info(f"Gefundene Frage: {matched_question['question']} -> Kategorie: {matched_question['category']}")
1184
+ answer = matched_question.get("answer", "Keine Antwort verfügbar")
1185
+ logging.info(f"Antwort: {answer}")
1186
+ return answer
1187
+ else:
1188
+ logging.warning("Keine passende Frage gefunden.")
1189
+ return None
1190
+
1191
+ def create_dashboard(category_nodes, activation_history, short_term_memory, mid_term_memory, long_term_memory):
1192
+ """
1193
+ Erstellt ein Dashboard zur Anzeige der Aktivierungshistorie, Gedächtnisverteilung und Netzwerktopologie.
1194
+
1195
+ Args:
1196
+ category_nodes (list): Liste der Kategorie-Knoten.
1197
+ activation_history (dict): Die Aktivierungshistorie.
1198
+ short_term_memory (list): Liste der Kurzzeitgedächtnisknoten.
1199
+ mid_term_memory (list): Liste der Mittelzeitgedächtnisknoten.
1200
+ long_term_memory (list): Liste der Langzeitgedächtnisknoten.
1201
+ """
1202
+ root = tk.Tk()
1203
+ root.title("Psyco Dashboard")
1204
+
1205
+ # Anzeige der Aktivierungshistorie
1206
+ activation_frame = ttk.Frame(root, padding="10")
1207
+ activation_frame.pack(fill=tk.BOTH, expand=True)
1208
+ activation_label = ttk.Label(activation_frame, text="Aktivierungshistorie")
1209
+ activation_label.pack()
1210
+ if activation_history:
1211
+ for label, activations in activation_history.items():
1212
+ fig, ax = plt.subplots()
1213
+ ax.plot(range(1, len(activations) + 1), activations)
1214
+ ax.set_title(label)
1215
+ canvas = FigureCanvasTkAgg(fig, master=activation_frame)
1216
+ canvas.draw()
1217
+ canvas.get_tk_widget().pack()
1218
+ else:
1219
+ no_data_label = ttk.Label(activation_frame, text="Keine Aktivierungshistorie verfügbar.")
1220
+ no_data_label.pack()
1221
+
1222
+ # Anzeige der Gedächtnisverteilung
1223
+ memory_frame = ttk.Frame(root, padding="10")
1224
+ memory_frame.pack(fill=tk.BOTH, expand=True)
1225
+ memory_label = ttk.Label(memory_frame, text="Gedächtnisverteilung")
1226
+ memory_label.pack()
1227
+ memory_counts = [len(short_term_memory), len(mid_term_memory), len(long_term_memory)]
1228
+ labels = ["Kurzfristig", "Mittelfristig", "Langfristig"]
1229
+ fig, ax = plt.subplots()
1230
+ ax.bar(labels, memory_counts, color=["red", "blue", "green"])
1231
+ ax.set_title("Verteilung der Gedächtnisknoten")
1232
+ ax.set_ylabel("Anzahl der Knoten")
1233
+ canvas = FigureCanvasTkAgg(fig, master=memory_frame)
1234
+ canvas.draw()
1235
+ canvas.get_tk_widget().pack()
1236
+
1237
+ # Anzeige der Netzwerktopologie
1238
+ topology_frame = ttk.Frame(root, padding="10")
1239
+ topology_frame.pack(fill=tk.BOTH, expand=True)
1240
+ topology_label = ttk.Label(topology_frame, text="Netzwerktopologie")
1241
+ topology_label.pack()
1242
+ G = nx.DiGraph()
1243
+ for node in category_nodes:
1244
+ G.add_node(node.label)
1245
+ for conn in node.connections:
1246
+ G.add_edge(node.label, conn.target_node.label, weight=conn.weight)
1247
+ pos = nx.spring_layout(G)
1248
+ edge_labels = {(u, v): d['weight'] for u, v, d in G.edges(data=True)}
1249
+ node_colors = ['skyblue' for _ in G.nodes()]
1250
+ fig, ax = plt.subplots()
1251
+ nx.draw(G, pos, with_labels=True, node_size=3000, node_color=node_colors, font_size=10, font_weight="bold", edge_color="gray", ax=ax)
1252
+ nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, ax=ax)
1253
+ ax.set_title("Netzwerktopologie")
1254
+ canvas = FigureCanvasTkAgg(fig, master=topology_frame)
1255
+ canvas.draw()
1256
+ canvas.get_tk_widget().pack()
1257
+
1258
+ # Anzeige der Heatmap der Aktivierungswerte
1259
+ heatmap_frame = ttk.Frame(root, padding="10")
1260
+ heatmap_frame.pack(fill=tk.BOTH, expand=True)
1261
+ heatmap_label = ttk.Label(heatmap_frame, text="Heatmap der Aktivierungswerte")
1262
+ heatmap_label.pack()
1263
+ if activation_history:
1264
+ min_length = min(len(activations) for activations in activation_history.values())
1265
+ truncated_activations = {key: values[:min_length] for key, values in activation_history.items()}
1266
+ heatmap_data = np.array([activations for activations in truncated_activations.values()])
1267
+ if heatmap_data.size > 0:
1268
+ fig, ax = plt.subplots()
1269
+ sns.heatmap(heatmap_data, cmap="YlGnBu", xticklabels=truncated_activations.keys(), yticklabels=False, ax=ax)
1270
+ ax.set_title("Heatmap der Aktivierungswerte")
1271
+ ax.set_xlabel("Kategorie")
1272
+ ax.set_ylabel("Epoche")
1273
+ canvas = FigureCanvasTkAgg(fig, master=heatmap_frame)
1274
+ canvas.draw()
1275
+ canvas.get_tk_widget().pack()
1276
+ else:
1277
+ no_data_label = ttk.Label(heatmap_frame, text="Heatmap-Daten sind leer. Überprüfen Sie die Aktivierungshistorie.")
1278
+ no_data_label.pack()
1279
+ else:
1280
+ no_data_label = ttk.Label(heatmap_frame, text="Keine Aktivierungshistorie verfügbar.")
1281
+ no_data_label.pack()
1282
+
1283
+ root.mainloop()
1284
+
1285
+ def process_csv_in_chunks(filename, chunk_size=10000):
1286
+ """
1287
+ Verarbeitet eine CSV-Datei in Chunks.
1288
+
1289
+ Args:
1290
+ filename (str): Der Pfad zur CSV-Datei.
1291
+ chunk_size (int): Die Anzahl der Zeilen pro Chunk.
1292
+
1293
+ Returns:
1294
+ pd.DataFrame: Die verarbeiteten Daten.
1295
+ """
1296
+ global category_nodes, questions
1297
+ logging.info(f"Beginne Verarbeitung der Datei: {filename}")
1298
+
1299
+ try:
1300
+ # Test, ob die Datei existiert
1301
+ if not os.path.exists(filename):
1302
+ logging.error(f"Datei {filename} nicht gefunden.")
1303
+ return None
1304
+
1305
+ all_chunks = []
1306
+ for chunk in pd.read_csv(filename, chunksize=chunk_size, encoding="utf-8", on_bad_lines='skip'):
1307
+ logging.info(f"Chunk mit {len(chunk)} Zeilen gelesen.")
1308
+ if 'Frage' not in chunk.columns or 'Kategorie' not in chunk.columns or 'Antwort' not in chunk.columns:
1309
+ logging.error("CSV-Datei enthält nicht die erwarteten Spalten: 'Frage', 'Kategorie', 'Antwort'")
1310
+ return None
1311
+
1312
+ all_chunks.append(chunk)
1313
+
1314
+ data = pd.concat(all_chunks, ignore_index=True)
1315
+ logging.info(f"Alle Chunks erfolgreich verarbeitet. Gesamtzeilen: {len(data)}")
1316
+
1317
+ return data
1318
+
1319
+ except pd.errors.EmptyDataError:
1320
+ logging.error("CSV-Datei ist leer.")
1321
+ except pd.errors.ParserError as e:
1322
+ logging.error(f"Parsing-Fehler in CSV-Datei: {e}")
1323
+ except Exception as e:
1324
+ logging.error(f"Unerwarteter Fehler beim Verarbeiten der Datei: {e}")
1325
+
1326
+ return None
1327
+
1328
+ def process_single_entry(question, category, answer):
1329
+ """
1330
+ Verarbeitet einen einzelnen Eintrag und fügt ihn dem Netzwerk hinzu.
1331
+
1332
+ Args:
1333
+ question (str): Die Frage.
1334
+ category (str): Die Kategorie.
1335
+ answer (str): Die Antwort.
1336
+ """
1337
+ global category_nodes, questions
1338
+
1339
+ # Sicherstellen, dass die globalen Variablen initialisiert sind
1340
+ if category_nodes is None:
1341
+ category_nodes = []
1342
+ logging.warning("Kategorie-Knotenliste war None, wurde nun initialisiert.")
1343
+
1344
+ if questions is None:
1345
+ questions = []
1346
+ logging.warning("Fragenliste war None, wurde nun initialisiert.")
1347
+
1348
+ # Überprüfen, ob die Kategorie bereits vorhanden ist
1349
+ if not any(node.label == category for node in category_nodes):
1350
+ category_nodes.append(Node(category))
1351
+ logging.info(f"Neue Kategorie '{category}' dem Netzwerk hinzugefügt.")
1352
+
1353
+ # Frage, Kategorie und Antwort zur Liste hinzufügen
1354
+ questions.append({"question": question, "category": category, "answer": answer})
1355
+ logging.info(f"Neue Frage hinzugefügt: '{question}' -> Kategorie: '{category}'")
1356
+
1357
+ def process_csv_with_dask(filename, chunk_size=10000):
1358
+ """
1359
+ Verarbeitet eine CSV-Datei mit Dask.
1360
+
1361
+ Args:
1362
+ filename (str): Der Pfad zur CSV-Datei.
1363
+ chunk_size (int): Die Anzahl der Zeilen pro Chunk.
1364
+ """
1365
+ try:
1366
+ ddf = dd.read_csv(filename, blocksize=chunk_size)
1367
+ ddf = ddf.astype({'Kategorie': 'category'})
1368
+
1369
+ for row in ddf.itertuples(index=False, name=None):
1370
+ process_single_entry(row[0], row[1], row[2])
1371
+
1372
+ logging.info("Alle Chunks erfolgreich mit Dask verarbeitet.")
1373
+ except Exception as e:
1374
+ logging.error(f"Fehler beim Verarbeiten der Datei mit Dask: {e}")
1375
+
1376
+ def save_to_sqlite(filename, db_name="dataset.db"):
1377
+ """
1378
+ Speichert die CSV-Daten in einer SQLite-Datenbank.
1379
+
1380
+ Args:
1381
+ filename (str): Der Pfad zur CSV-Datei.
1382
+ db_name (str): Der Name der SQLite-Datenbank.
1383
+ """
1384
+ conn = sqlite3.connect(db_name)
1385
+ chunk_iter = pd.read_csv(filename, chunksize=10000)
1386
+ for chunk in chunk_iter:
1387
+ chunk.to_sql("qa_data", conn, if_exists="append", index=False)
1388
+ logging.info(f"Chunk mit {len(chunk)} Zeilen gespeichert.")
1389
+ conn.close()
1390
+ logging.info("CSV-Daten wurden erfolgreich in SQLite gespeichert.")
1391
+
1392
+ def load_from_sqlite(db_name="dataset.db"):
1393
+ """
1394
+ Lädt die Daten aus einer SQLite-Datenbank.
1395
+
1396
+ Args:
1397
+ db_name (str): Der Name der SQLite-Datenbank.
1398
+
1399
+ Returns:
1400
+ pd.DataFrame: Die geladenen Daten.
1401
+ """
1402
+ conn = sqlite3.connect(db_name)
1403
+ query = "SELECT Frage, Kategorie, Antwort FROM qa_data"
1404
+ data = pd.read_sql_query(query, conn)
1405
+ conn.close()
1406
+ return data
1407
+
1408
+ def save_partial_model(filename="partial_model.json"):
1409
+ """
1410
+ Speichert ein Teilmodell in einer JSON-Datei.
1411
+
1412
+ Args:
1413
+ filename (str): Der Dateiname der JSON-Datei.
1414
+ """
1415
+ model_data = {
1416
+ "nodes": [node.save_state() for node in category_nodes],
1417
+ "questions": questions
1418
+ }
1419
+ with open(filename, "w") as file:
1420
+ json.dump(model_data, file, indent=4)
1421
+ logging.info("Teilmodell gespeichert.")
1422
+
1423
+ def lazy_load_csv(filename, chunk_size=10000):
1424
+ """
1425
+ Lädt eine CSV-Datei faul in Chunks.
1426
+
1427
+ Args:
1428
+ filename (str): Der Pfad zur CSV-Datei.
1429
+ chunk_size (int): Die Anzahl der Zeilen pro Chunk.
1430
+
1431
+ Yields:
1432
+ tuple: Die Frage, Kategorie und Antwort.
1433
+ """
1434
+ for chunk in pd.read_csv(filename, chunksize=chunk_size):
1435
+ for _, row in chunk.iterrows():
1436
+ yield row['Frage'], row['Kategorie'], row['Antwort']
1437
+
1438
+ def main():
1439
+ """
1440
+ Hauptfunktion zum Ausführen der Simulation.
1441
+ """
1442
+ start_time = time.time()
1443
+ category_nodes, questions = load_model_with_questions_and_answers("model_with_qa.json")
1444
+
1445
+ if category_nodes is None:
1446
+ csv_file = "data.csv"
1447
+ data = process_csv_in_chunks(csv_file)
1448
+ if data is None:
1449
+ logging.error("Fehler beim Laden der CSV-Datei.")
1450
+ return
1451
+
1452
+ if len(data) > 1000:
1453
+ logging.info("Datei hat mehr als 1000 Zeilen. Aufteilen in kleinere Dateien...")
1454
+ split_csv(csv_file)
1455
+
1456
+ # Verarbeite jede aufgeteilte Datei
1457
+ data_dir = "data"
1458
+ for filename in os.listdir(data_dir):
1459
+ if filename.endswith(".csv"):
1460
+ file_path = os.path.join(data_dir, filename)
1461
+ logging.info(f"Verarbeite Datei: {file_path}")
1462
+
1463
+ data = process_csv_in_chunks(file_path)
1464
+ if data is None:
1465
+ logging.error("Fehler beim Laden der CSV-Datei.")
1466
+ return
1467
+
1468
+ categories = data['Kategorie'].unique()
1469
+ category_nodes = initialize_quiz_network(categories)
1470
+ questions = [{"question": row['Frage'], "category": row['Kategorie'], "answer": row['Antwort']} for _, row in data.iterrows()]
1471
+
1472
+ personality_distributions = {category: random.uniform(0.5, 0.8) for category in [node.label for node in category_nodes]}
1473
+ activation_history, weights_history = simulate_learning(data, category_nodes, personality_distributions)
1474
+
1475
+ save_model_with_questions_and_answers(category_nodes, questions)
1476
+ else:
1477
+ logging.info("Datei hat weniger als 1000 Zeilen. Keine Aufteilung erforderlich.")
1478
+ categories = data['Kategorie'].unique()
1479
+ category_nodes = initialize_quiz_network(categories)
1480
+ questions = [{"question": row['Frage'], "category": row['Kategorie'], "answer": row['Antwort']} for _, row in data.iterrows()]
1481
+
1482
+ personality_distributions = {category: random.uniform(0.5, 0.8) for category in [node.label for node in category_nodes]}
1483
+ activation_history, weights_history = simulate_learning(data, category_nodes, personality_distributions)
1484
+
1485
+ save_model_with_questions_and_answers(category_nodes, questions)
1486
+
1487
+ end_time = time.time()
1488
+ logging.info(f"Simulation abgeschlossen. Gesamtdauer: {end_time - start_time:.2f} Sekunden")
1489
+
1490
+ def run_simulation_from_gui(learning_rate, decay_rate, reward_interval, epochs):
1491
+ """
1492
+ Führt die Simulation aus der GUI aus.
1493
+
1494
+ Args:
1495
+ learning_rate (float): Die Lernrate.
1496
+ decay_rate (float): Die Verfallsrate.
1497
+ reward_interval (int): Das Belohnungsintervall.
1498
+ epochs (int): Die Anzahl der Epochen.
1499
+ """
1500
+ global model_saved
1501
+ model_saved = False # Erzwinge das Speichern nach dem Training
1502
+
1503
+ start_time = time.time()
1504
+ csv_file = "data.csv"
1505
+
1506
+ category_nodes, questions = load_model_with_questions_and_answers("model_with_qa.json")
1507
+
1508
+ if category_nodes is None:
1509
+ data = process_csv_in_chunks(csv_file)
1510
+ if not isinstance(data, pd.DataFrame):
1511
+ logging.error("Fehler beim Laden der CSV-Datei. Erwarteter DataFrame wurde nicht zurückgegeben.")
1512
+ return
1513
+
1514
+ if len(data) > 1000:
1515
+ logging.info("Datei hat mehr als 1000 Zeilen. Aufteilen in kleinere Dateien...")
1516
+ split_csv(csv_file)
1517
+
1518
+ # Verarbeite jede aufgeteilte Datei
1519
+ data_dir = "data"
1520
+ for filename in os.listdir(data_dir):
1521
+ if filename.endswith(".csv"):
1522
+ file_path = os.path.join(data_dir, filename)
1523
+ logging.info(f"Verarbeite Datei: {file_path}")
1524
+
1525
+ data = process_csv_in_chunks(file_path)
1526
+ if not isinstance(data, pd.DataFrame):
1527
+ logging.error("Fehler beim Laden der CSV-Datei. Erwarteter DataFrame wurde nicht zurückgegeben.")
1528
+ return
1529
+
1530
+ categories = data['Kategorie'].unique()
1531
+ category_nodes = initialize_quiz_network(categories)
1532
+ questions = [{"question": row['Frage'], "category": row['Kategorie'], "answer": row['Antwort']} for _, row in data.iterrows()]
1533
+
1534
+ personality_distributions = {category: random.uniform(0.5, 0.8) for category in [node.label for node in category_nodes]}
1535
+ activation_history, weights_history = simulate_learning(
1536
+ data, category_nodes, personality_distributions,
1537
+ epochs=int(epochs),
1538
+ learning_rate=float(learning_rate),
1539
+ reward_interval=int(reward_interval),
1540
+ decay_rate=float(decay_rate)
1541
+ )
1542
+
1543
+ save_model_with_questions_and_answers(category_nodes, questions)
1544
+ else:
1545
+ logging.info("Datei hat weniger als 1000 Zeilen. Keine Aufteilung erforderlich.")
1546
+ categories = data['Kategorie'].unique()
1547
+ category_nodes = initialize_quiz_network(categories)
1548
+ questions = [{"question": row['Frage'], "category": row['Kategorie'], "answer": row['Antwort']} for _, row in data.iterrows()]
1549
+
1550
+ personality_distributions = {category: random.uniform(0.5, 0.8) for category in [node.label for node in category_nodes]}
1551
+ activation_history, weights_history = simulate_learning(
1552
+ data, category_nodes, personality_distributions,
1553
+ epochs=int(epochs),
1554
+ learning_rate=float(learning_rate),
1555
+ reward_interval=int(reward_interval),
1556
+ decay_rate=float(decay_rate)
1557
+ )
1558
+
1559
+ save_model_with_questions_and_answers(category_nodes, questions)
1560
+ else:
1561
+ data = process_csv_in_chunks(csv_file)
1562
+ if not isinstance(data, pd.DataFrame):
1563
+ logging.error("Fehler beim Laden der CSV-Datei. Erwarteter DataFrame wurde nicht zurückgegeben.")
1564
+ return
1565
+
1566
+ logging.info(f"Anzahl der Zeilen in der geladenen CSV: {len(data)}")
1567
+
1568
+ personality_distributions = {category: random.uniform(0.5, 0.8) for category in [node.label for node in category_nodes]}
1569
+
1570
+ activation_history, weights_history = simulate_learning(
1571
+ data, category_nodes, personality_distributions,
1572
+ epochs=int(epochs),
1573
+ learning_rate=float(learning_rate),
1574
+ reward_interval=int(reward_interval),
1575
+ decay_rate=float(decay_rate)
1576
+ )
1577
+
1578
+ save_model_with_questions_and_answers(category_nodes, questions)
1579
+
1580
+ end_time = time.time()
1581
+ logging.info(f"Simulation abgeschlossen. Gesamtdauer: {end_time - start_time:.2f} Sekunden")
1582
+ messagebox.showinfo("Ergebnis", f"Simulation abgeschlossen! Dauer: {end_time - start_time:.2f} Sekunden")
1583
+
1584
+ def async_initialize_network():
1585
+ """
1586
+ Initialisiert das Netzwerk asynchron.
1587
+ """
1588
+ global category_nodes, questions, model_saved
1589
+ logging.info("Starte Initialisierung des Netzwerks...")
1590
+
1591
+ category_nodes, questions = load_model_with_questions_and_answers("model_with_qa.json")
1592
+
1593
+ if category_nodes is None:
1594
+ category_nodes = []
1595
+ logging.warning("Keine gespeicherten Kategorien gefunden. Neues Netzwerk wird erstellt.")
1596
+ model_saved = False # Zurücksetzen der Speicher-Flagge
1597
+
1598
+ if questions is None:
1599
+ questions = []
1600
+ logging.warning("Keine gespeicherten Fragen gefunden. Neues Fragen-Array wird erstellt.")
1601
+ model_saved = False # Zurücksetzen der Speicher-Flagge
1602
+
1603
+ if not category_nodes:
1604
+ csv_file = "data.csv"
1605
+ data = process_csv_in_chunks(csv_file)
1606
+ if isinstance(data, pd.DataFrame):
1607
+ if len(data) > 1000:
1608
+ logging.info("Datei hat mehr als 1000 Zeilen. Aufteilen in kleinere Dateien...")
1609
+ split_csv(csv_file)
1610
+
1611
+ # Verarbeite jede aufgeteilte Datei
1612
+ data_dir = "data"
1613
+ for filename in os.listdir(data_dir):
1614
+ if filename.endswith(".csv"):
1615
+ file_path = os.path.join(data_dir, filename)
1616
+ logging.info(f"Verarbeite Datei: {file_path}")
1617
+
1618
+ data = process_csv_in_chunks(file_path)
1619
+ if isinstance(data, pd.DataFrame):
1620
+ categories = data['Kategorie'].unique()
1621
+ category_nodes = initialize_quiz_network(categories)
1622
+ questions = [{"question": row['Frage'], "category": row['Kategorie'], "answer": row['Antwort']} for _, row in data.iterrows()]
1623
+ logging.info("Netzwerk aus CSV-Daten erfolgreich erstellt.")
1624
+ model_saved = False # Zurücksetzen der Speicher-Flagge
1625
+ else:
1626
+ logging.info("Datei hat weniger als 1000 Zeilen. Keine Aufteilung erforderlich.")
1627
+ categories = data['Kategorie'].unique()
1628
+ category_nodes = initialize_quiz_network(categories)
1629
+ questions = [{"question": row['Frage'], "category": row['Kategorie'], "answer": row['Antwort']} for _, row in data.iterrows()]
1630
+ logging.info("Netzwerk aus CSV-Daten erfolgreich erstellt.")
1631
+ model_saved = False # Zurücksetzen der Speicher-Flagge
1632
+ else:
1633
+ logging.error("Fehler beim Laden der CSV-Daten. Netzwerk konnte nicht initialisiert werden.")
1634
+ return
1635
+
1636
+ save_model_with_questions_and_answers(category_nodes, questions)
1637
+ logging.info("Netzwerk erfolgreich initialisiert.")
1638
+
1639
+ def start_gui():
1640
+ """
1641
+ Startet die GUI.
1642
+ """
1643
+ def start_simulation():
1644
+ try:
1645
+ threading.Thread(target=run_simulation_from_gui, args=(0.8, 0.002, 5, 10), daemon=True).start()
1646
+ messagebox.showinfo("Info", "Simulation gestartet!")
1647
+ logging.info("Simulation gestartet")
1648
+ except Exception as e:
1649
+ logging.error(f"Fehler beim Start der Simulation: {e}")
1650
+ messagebox.showerror("Fehler", f"Fehler: {e}")
1651
+
1652
+ root = tk.Tk()
1653
+ root.title("DRLCogNet GUI")
1654
+ root.geometry("400x300")
1655
+
1656
+ header_label = tk.Label(root, text="Simulationseinstellungen", font=("Helvetica", 16))
1657
+ header_label.pack(pady=10)
1658
+
1659
+ start_button = tk.Button(root, text="Simulation starten", command=start_simulation)
1660
+ start_button.pack(pady=20)
1661
+
1662
+ root.mainloop()
1663
+
1664
+ if __name__ == "__main__":
1665
+ # Starte die Initialisierung in einem Thread
1666
+ threading.Thread(target=async_initialize_network, daemon=True).start()
1667
+ start_gui()