evonet 0.1.0.dev18__tar.gz → 0.1.0.dev20__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/PKG-INFO +1 -1
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/core.py +9 -1
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/mutation.py +41 -18
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet.egg-info/PKG-INFO +1 -1
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/pyproject.toml +1 -1
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/LICENSE +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/README.md +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/__init__.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/activation.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/connection.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/core_mit_plot_simple.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/enums.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/io.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/layer.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/neuron.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/serialization.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/utils.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet/visualize.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet.egg-info/SOURCES.txt +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet.egg-info/dependency_links.txt +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet.egg-info/requires.txt +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/evonet.egg-info/top_level.txt +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/setup.cfg +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/tests/test_activation.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/tests/test_core.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/tests/test_nnet_io_and_forward.py +0 -0
- {evonet-0.1.0.dev18 → evonet-0.1.0.dev20}/tests/test_recurrent_dynamics.py +0 -0
|
@@ -255,7 +255,7 @@ class Nnet:
|
|
|
255
255
|
target: Neuron,
|
|
256
256
|
weight: float | None = None,
|
|
257
257
|
conn_type: ConnectionType = ConnectionType.STANDARD,
|
|
258
|
-
) -> None:
|
|
258
|
+
) -> Connection | None:
|
|
259
259
|
"""
|
|
260
260
|
Create a directed connection between two neurons.
|
|
261
261
|
|
|
@@ -264,8 +264,14 @@ class Nnet:
|
|
|
264
264
|
target (Neuron): Target neuron.
|
|
265
265
|
weight (float | None): Initial weight. If None, 0.0 is used.
|
|
266
266
|
conn_type (ConnectionType): Type of connection (e.g. standard, recurrent).
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
Connection: Added Connection.
|
|
267
270
|
"""
|
|
268
271
|
|
|
272
|
+
if any(c.target == target for c in source.outgoing):
|
|
273
|
+
return None # duplicate
|
|
274
|
+
|
|
269
275
|
if weight is None:
|
|
270
276
|
weight = 0.0
|
|
271
277
|
|
|
@@ -273,6 +279,8 @@ class Nnet:
|
|
|
273
279
|
source.outgoing.append(conn)
|
|
274
280
|
target.incoming.append(conn)
|
|
275
281
|
|
|
282
|
+
return conn
|
|
283
|
+
|
|
276
284
|
def reset(self, full: bool = False) -> None:
|
|
277
285
|
"""Reset all neurons (clears input, output, and caches)."""
|
|
278
286
|
for layer in self.layers:
|
|
@@ -154,7 +154,7 @@ def add_random_connection(
|
|
|
154
154
|
net: Nnet,
|
|
155
155
|
allowed_recurrent: Optional[Collection[RecurrentKind | str]] = None,
|
|
156
156
|
connection_init: Literal["zero", "random", "near_zero"] = "zero",
|
|
157
|
-
) ->
|
|
157
|
+
) -> Connection | None:
|
|
158
158
|
"""
|
|
159
159
|
Add a valid connection between two randomly chosen neurons.
|
|
160
160
|
|
|
@@ -178,7 +178,7 @@ def add_random_connection(
|
|
|
178
178
|
- "near_zero": Weight ~ U(-0.05, 0.05)
|
|
179
179
|
|
|
180
180
|
Returns:
|
|
181
|
-
|
|
181
|
+
Connection: New connection, None otherwise.
|
|
182
182
|
"""
|
|
183
183
|
|
|
184
184
|
# Weight initialization
|
|
@@ -192,7 +192,7 @@ def add_random_connection(
|
|
|
192
192
|
|
|
193
193
|
all_neurons = net.get_all_neurons()
|
|
194
194
|
if len(all_neurons) < 2:
|
|
195
|
-
return
|
|
195
|
+
return None
|
|
196
196
|
|
|
197
197
|
# Build a dict of existing connections
|
|
198
198
|
existing: set[tuple[Neuron, Neuron]] = {
|
|
@@ -230,7 +230,7 @@ def add_random_connection(
|
|
|
230
230
|
candidates.append((src, dst)) # recurrent allowed by policy
|
|
231
231
|
|
|
232
232
|
if not candidates:
|
|
233
|
-
return
|
|
233
|
+
return None
|
|
234
234
|
|
|
235
235
|
src, dst = random.choice(candidates)
|
|
236
236
|
src_layer_idx, dst_layer_idx = layer_of[src], layer_of[dst]
|
|
@@ -240,24 +240,31 @@ def add_random_connection(
|
|
|
240
240
|
else ConnectionType.RECURRENT
|
|
241
241
|
)
|
|
242
242
|
|
|
243
|
-
net.add_connection(src, dst, weight=weight, conn_type=conn_type)
|
|
244
|
-
|
|
243
|
+
conn = net.add_connection(src, dst, weight=weight, conn_type=conn_type)
|
|
244
|
+
|
|
245
|
+
return conn
|
|
245
246
|
|
|
246
247
|
|
|
247
|
-
def remove_random_connection(net: Nnet) ->
|
|
248
|
+
def remove_random_connection(net: Nnet) -> bool:
|
|
248
249
|
"""
|
|
249
250
|
Remove a randomly selected connection from the network.
|
|
250
251
|
|
|
251
252
|
Does nothing if no connections are present.
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
bool: True if a connection was removed, False otherwise.
|
|
252
256
|
"""
|
|
257
|
+
|
|
253
258
|
all_connections = net.get_all_connections()
|
|
254
259
|
if not all_connections:
|
|
255
|
-
return
|
|
260
|
+
return False
|
|
256
261
|
|
|
257
262
|
conn = random.choice(all_connections)
|
|
258
263
|
conn.source.outgoing.remove(conn)
|
|
259
264
|
conn.target.incoming.remove(conn)
|
|
260
265
|
|
|
266
|
+
return True
|
|
267
|
+
|
|
261
268
|
|
|
262
269
|
def add_random_neuron(
|
|
263
270
|
net: Nnet,
|
|
@@ -265,7 +272,7 @@ def add_random_neuron(
|
|
|
265
272
|
connection_init: Literal["zero", "random", "near_zero", "none"] = "zero",
|
|
266
273
|
connection_scope: Literal["adjacent", "crosslayer"] = "adjacent",
|
|
267
274
|
connection_density: float = 1.0,
|
|
268
|
-
) -> None:
|
|
275
|
+
) -> Neuron | None:
|
|
269
276
|
"""
|
|
270
277
|
Insert a new hidden neuron into a random layer.
|
|
271
278
|
|
|
@@ -275,9 +282,13 @@ def add_random_neuron(
|
|
|
275
282
|
net (Nnet): The target network.
|
|
276
283
|
activations (list[str] | None): Optional list of allowed activation functions.
|
|
277
284
|
If None, all registered activations are used.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
Neuron: Added neurons, or None
|
|
278
288
|
"""
|
|
289
|
+
|
|
279
290
|
if len(net.layers) < 2:
|
|
280
|
-
return
|
|
291
|
+
return None
|
|
281
292
|
|
|
282
293
|
if len(net.layers) == 2:
|
|
283
294
|
net.insert_layer(1)
|
|
@@ -285,21 +296,23 @@ def add_random_neuron(
|
|
|
285
296
|
# Choose target layer (not input, not output)
|
|
286
297
|
candidate_layers = net.layers[1:-1]
|
|
287
298
|
if not candidate_layers:
|
|
288
|
-
return
|
|
299
|
+
return None
|
|
289
300
|
|
|
290
301
|
layer = random.choice(candidate_layers)
|
|
291
302
|
|
|
292
|
-
net.add_neuron(
|
|
303
|
+
new_neuron = net.add_neuron(
|
|
293
304
|
layer_idx=net.layers.index(layer),
|
|
294
305
|
activation=random_function_name(activations),
|
|
295
306
|
role=NeuronRole.HIDDEN,
|
|
296
307
|
connection_init=connection_init,
|
|
297
308
|
connection_scope=connection_scope,
|
|
298
309
|
connection_density=connection_density,
|
|
299
|
-
)
|
|
310
|
+
)[0]
|
|
311
|
+
|
|
312
|
+
return new_neuron
|
|
300
313
|
|
|
301
314
|
|
|
302
|
-
def remove_random_neuron(net: Nnet) ->
|
|
315
|
+
def remove_random_neuron(net: Nnet) -> bool:
|
|
303
316
|
"""
|
|
304
317
|
Remove a randomly selected hidden neuron from the network.
|
|
305
318
|
|
|
@@ -307,7 +320,7 @@ def remove_random_neuron(net: Nnet) -> None:
|
|
|
307
320
|
"""
|
|
308
321
|
hidden_neurons = [n for n in net.get_all_neurons() if n.role == NeuronRole.HIDDEN]
|
|
309
322
|
if not hidden_neurons:
|
|
310
|
-
return
|
|
323
|
+
return False
|
|
311
324
|
|
|
312
325
|
neuron = random.choice(hidden_neurons)
|
|
313
326
|
|
|
@@ -323,8 +336,12 @@ def remove_random_neuron(net: Nnet) -> None:
|
|
|
323
336
|
layer.neurons.remove(neuron)
|
|
324
337
|
break
|
|
325
338
|
|
|
339
|
+
return True
|
|
340
|
+
|
|
326
341
|
|
|
327
|
-
def split_connection(
|
|
342
|
+
def split_connection(
|
|
343
|
+
net: Nnet, activation: str = "tanh", noise: float = 0.1
|
|
344
|
+
) -> Neuron | None:
|
|
328
345
|
"""
|
|
329
346
|
Insert a neuron in the middle of an existing connection.
|
|
330
347
|
|
|
@@ -336,10 +353,14 @@ def split_connection(net: Nnet, activation: str = "tanh", noise: float = 0.1) ->
|
|
|
336
353
|
net (Nnet): The target network.
|
|
337
354
|
activation (str): Activation function for the new neuron.
|
|
338
355
|
noise (float): Optional noise applied to new weights.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
Neuron: Added neuron, or None
|
|
339
359
|
"""
|
|
360
|
+
|
|
340
361
|
all_connections = net.get_all_connections()
|
|
341
362
|
if not all_connections:
|
|
342
|
-
return
|
|
363
|
+
return None
|
|
343
364
|
|
|
344
365
|
conn = random.choice(all_connections)
|
|
345
366
|
src, dst = conn.source, conn.target
|
|
@@ -351,7 +372,7 @@ def split_connection(net: Nnet, activation: str = "tanh", noise: float = 0.1) ->
|
|
|
351
372
|
break
|
|
352
373
|
|
|
353
374
|
if insert_idx is None or insert_idx >= len(net.layers):
|
|
354
|
-
return
|
|
375
|
+
return None
|
|
355
376
|
|
|
356
377
|
new_neuron = net.add_neuron(
|
|
357
378
|
layer_idx=insert_idx,
|
|
@@ -367,3 +388,5 @@ def split_connection(net: Nnet, activation: str = "tanh", noise: float = 0.1) ->
|
|
|
367
388
|
weight = 1.0 + np.random.normal(0, noise)
|
|
368
389
|
net.add_connection(src, new_neuron, weight=weight)
|
|
369
390
|
net.add_connection(new_neuron, dst, weight=conn.weight)
|
|
391
|
+
|
|
392
|
+
return new_neuron
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|