evonet 0.1.0.dev17__tar.gz → 0.1.0.dev19__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.dev17 → evonet-0.1.0.dev19}/PKG-INFO +1 -1
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/core.py +9 -1
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/mutation.py +41 -16
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet.egg-info/PKG-INFO +1 -1
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/pyproject.toml +1 -1
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/LICENSE +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/README.md +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/__init__.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/activation.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/connection.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/core_mit_plot_simple.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/enums.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/io.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/layer.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/neuron.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/serialization.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/utils.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet/visualize.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet.egg-info/SOURCES.txt +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet.egg-info/dependency_links.txt +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet.egg-info/requires.txt +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/evonet.egg-info/top_level.txt +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/setup.cfg +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/tests/test_activation.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/tests/test_core.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/tests/test_nnet_io_and_forward.py +0 -0
- {evonet-0.1.0.dev17 → evonet-0.1.0.dev19}/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,30 +240,39 @@ 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,
|
|
264
271
|
activations: list[str] | None = None,
|
|
265
272
|
connection_init: Literal["zero", "random", "near_zero", "none"] = "zero",
|
|
266
|
-
|
|
273
|
+
connection_scope: Literal["adjacent", "crosslayer"] = "adjacent",
|
|
274
|
+
connection_density: float = 1.0,
|
|
275
|
+
) -> Neuron | None:
|
|
267
276
|
"""
|
|
268
277
|
Insert a new hidden neuron into a random layer.
|
|
269
278
|
|
|
@@ -273,9 +282,13 @@ def add_random_neuron(
|
|
|
273
282
|
net (Nnet): The target network.
|
|
274
283
|
activations (list[str] | None): Optional list of allowed activation functions.
|
|
275
284
|
If None, all registered activations are used.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
Neuron: Added neurons, or None
|
|
276
288
|
"""
|
|
289
|
+
|
|
277
290
|
if len(net.layers) < 2:
|
|
278
|
-
return
|
|
291
|
+
return None
|
|
279
292
|
|
|
280
293
|
if len(net.layers) == 2:
|
|
281
294
|
net.insert_layer(1)
|
|
@@ -283,16 +296,20 @@ def add_random_neuron(
|
|
|
283
296
|
# Choose target layer (not input, not output)
|
|
284
297
|
candidate_layers = net.layers[1:-1]
|
|
285
298
|
if not candidate_layers:
|
|
286
|
-
return
|
|
299
|
+
return None
|
|
287
300
|
|
|
288
301
|
layer = random.choice(candidate_layers)
|
|
289
302
|
|
|
290
|
-
net.add_neuron(
|
|
303
|
+
new_neuron = net.add_neuron(
|
|
291
304
|
layer_idx=net.layers.index(layer),
|
|
292
305
|
activation=random_function_name(activations),
|
|
293
306
|
role=NeuronRole.HIDDEN,
|
|
294
307
|
connection_init=connection_init,
|
|
295
|
-
|
|
308
|
+
connection_scope=connection_scope,
|
|
309
|
+
connection_density=connection_density,
|
|
310
|
+
)[0]
|
|
311
|
+
|
|
312
|
+
return new_neuron
|
|
296
313
|
|
|
297
314
|
|
|
298
315
|
def remove_random_neuron(net: Nnet) -> None:
|
|
@@ -320,7 +337,9 @@ def remove_random_neuron(net: Nnet) -> None:
|
|
|
320
337
|
break
|
|
321
338
|
|
|
322
339
|
|
|
323
|
-
def split_connection(
|
|
340
|
+
def split_connection(
|
|
341
|
+
net: Nnet, activation: str = "tanh", noise: float = 0.1
|
|
342
|
+
) -> Neuron | None:
|
|
324
343
|
"""
|
|
325
344
|
Insert a neuron in the middle of an existing connection.
|
|
326
345
|
|
|
@@ -332,10 +351,14 @@ def split_connection(net: Nnet, activation: str = "tanh", noise: float = 0.1) ->
|
|
|
332
351
|
net (Nnet): The target network.
|
|
333
352
|
activation (str): Activation function for the new neuron.
|
|
334
353
|
noise (float): Optional noise applied to new weights.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
Neuron: Added neuron, or None
|
|
335
357
|
"""
|
|
358
|
+
|
|
336
359
|
all_connections = net.get_all_connections()
|
|
337
360
|
if not all_connections:
|
|
338
|
-
return
|
|
361
|
+
return None
|
|
339
362
|
|
|
340
363
|
conn = random.choice(all_connections)
|
|
341
364
|
src, dst = conn.source, conn.target
|
|
@@ -347,7 +370,7 @@ def split_connection(net: Nnet, activation: str = "tanh", noise: float = 0.1) ->
|
|
|
347
370
|
break
|
|
348
371
|
|
|
349
372
|
if insert_idx is None or insert_idx >= len(net.layers):
|
|
350
|
-
return
|
|
373
|
+
return None
|
|
351
374
|
|
|
352
375
|
new_neuron = net.add_neuron(
|
|
353
376
|
layer_idx=insert_idx,
|
|
@@ -363,3 +386,5 @@ def split_connection(net: Nnet, activation: str = "tanh", noise: float = 0.1) ->
|
|
|
363
386
|
weight = 1.0 + np.random.normal(0, noise)
|
|
364
387
|
net.add_connection(src, new_neuron, weight=weight)
|
|
365
388
|
net.add_connection(new_neuron, dst, weight=conn.weight)
|
|
389
|
+
|
|
390
|
+
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
|