evonet 0.1.0.dev13__tar.gz → 0.1.0.dev15__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.
Files changed (28) hide show
  1. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/PKG-INFO +1 -1
  2. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/core.py +7 -8
  3. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/enums.py +18 -0
  4. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/mutation.py +8 -10
  5. evonet-0.1.0.dev15/evonet/utils.py +28 -0
  6. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet.egg-info/PKG-INFO +1 -1
  7. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/pyproject.toml +1 -1
  8. evonet-0.1.0.dev13/evonet/utils.py +0 -0
  9. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/LICENSE +0 -0
  10. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/README.md +0 -0
  11. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/__init__.py +0 -0
  12. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/activation.py +0 -0
  13. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/connection.py +0 -0
  14. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/core_mit_plot_simple.py +0 -0
  15. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/io.py +0 -0
  16. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/layer.py +0 -0
  17. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/neuron.py +0 -0
  18. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/serialization.py +0 -0
  19. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet/visualize.py +0 -0
  20. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet.egg-info/SOURCES.txt +0 -0
  21. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet.egg-info/dependency_links.txt +0 -0
  22. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet.egg-info/requires.txt +0 -0
  23. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/evonet.egg-info/top_level.txt +0 -0
  24. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/setup.cfg +0 -0
  25. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/tests/test_activation.py +0 -0
  26. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/tests/test_core.py +0 -0
  27. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/tests/test_nnet_io_and_forward.py +0 -0
  28. {evonet-0.1.0.dev13 → evonet-0.1.0.dev15}/tests/test_recurrent_dynamics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evonet
3
- Version: 0.1.0.dev13
3
+ Version: 0.1.0.dev15
4
4
  Summary: Evolvable neural network core for integration with EvoLib
5
5
  Author-email: EvoLib <evolib@dismail.de>
6
6
  License: MIT License
@@ -20,6 +20,7 @@ from evonet.connection import Connection
20
20
  from evonet.enums import ConnectionType, NeuronRole, RecurrentKind
21
21
  from evonet.layer import Layer
22
22
  from evonet.neuron import Neuron
23
+ from evonet.utils import connection_init_value
23
24
 
24
25
 
25
26
  class Nnet:
@@ -102,7 +103,7 @@ class Nnet:
102
103
  label: str = "",
103
104
  role: NeuronRole = NeuronRole.HIDDEN,
104
105
  count: int = 1,
105
- connection_init: Literal["random", "zero", "none"] = "random",
106
+ connection_init: Literal["random", "zero", "near_zero", "none"] = "zero",
106
107
  recurrent: Optional[set[RecurrentKind]] = None,
107
108
  ) -> list[Neuron]:
108
109
  """
@@ -116,9 +117,10 @@ class Nnet:
116
117
  role: Role of the neuron (INPUT, HIDDEN, OUTPUT).
117
118
  count: Number of neurons to add (default: 1).
118
119
  connection_init:
119
- "random" – connect with random weights (feedforward + recurrent)
120
- "zero" – connect with weight 0.0 (feedforward + recurrent)
121
- "none" – do not create connections (feedforward + recurrent)
120
+ "random" - connect with random weights (feedforward + recurrent)
121
+ "zero" - connect with weight 0.0 (feedforward + recurrent)
122
+ "near_zero" - connect with small random weights (-0.05, 0.05)
123
+ "none" - do not create connections (feedforward + recurrent)
122
124
  recurrent: Optional recurrent connection types.
123
125
 
124
126
  Returns:
@@ -144,10 +146,7 @@ class Nnet:
144
146
  new_neurons.append(neuron)
145
147
 
146
148
  # Weights based on init mode
147
- weight_map = {"random": None, "zero": 0.0, "none": None}
148
- if connection_init not in weight_map:
149
- raise ValueError(f"Invalid connection_init: {connection_init}")
150
- weight = weight_map[connection_init]
149
+ weight = connection_init_value(connection_init)
151
150
 
152
151
  skip_connections = connection_init == "none"
153
152
 
@@ -48,3 +48,21 @@ class RecurrentKind(str, Enum):
48
48
  DIRECT = "direct" # src == dst
49
49
  LATERAL = "lateral" # same layer, src != dst
50
50
  INDIRECT = "indirect" # src_layer > dst_layer (back edge)
51
+
52
+
53
+ # Neutral activation functions
54
+ # These functions satisfy f(0) ≈ 0 and are safe for zero-weight initialization.
55
+ NEUTRAL_ACTIVATIONS: list[str] = [
56
+ "tanh",
57
+ "relu",
58
+ "relu_max1",
59
+ "leaky_relu",
60
+ "elu",
61
+ "selu",
62
+ "linear",
63
+ "linear_max1",
64
+ "invert",
65
+ "swish",
66
+ "mish",
67
+ "softsign",
68
+ ]
@@ -19,6 +19,7 @@ from evonet.connection import Connection
19
19
  from evonet.core import Nnet
20
20
  from evonet.enums import ConnectionType, NeuronRole, RecurrentKind
21
21
  from evonet.neuron import Neuron
22
+ from evonet.utils import connection_init_value
22
23
 
23
24
  ALL_ACTIVATIONS = "all"
24
25
 
@@ -181,14 +182,7 @@ def add_random_connection(
181
182
  """
182
183
 
183
184
  # Weight initialization
184
- if connection_init == "zero":
185
- weight = 0.0
186
- elif connection_init == "random":
187
- weight = np.random.randn() * 0.5
188
- elif connection_init == "near_zero":
189
- weight = np.random.uniform(-0.05, 0.05)
190
- else:
191
- raise ValueError(f"Unknown init mode: {connection_init}")
185
+ weight = connection_init_value(connection_init)
192
186
 
193
187
  # normalize to set[RecurrentKind]
194
188
  kinds: set[RecurrentKind] = set()
@@ -265,7 +259,11 @@ def remove_random_connection(net: Nnet) -> None:
265
259
  conn.target.incoming.remove(conn)
266
260
 
267
261
 
268
- def add_random_neuron(net: Nnet, activations: list[str] | None = None) -> None:
262
+ def add_random_neuron(
263
+ net: Nnet,
264
+ activations: list[str] | None = None,
265
+ connection_init: Literal["zero", "random", "near_zero", "none"] = "zero",
266
+ ) -> None:
269
267
  """
270
268
  Insert a new hidden neuron into a random layer.
271
269
 
@@ -293,7 +291,7 @@ def add_random_neuron(net: Nnet, activations: list[str] | None = None) -> None:
293
291
  layer_idx=net.layers.index(layer),
294
292
  activation=random_function_name(activations),
295
293
  role=NeuronRole.HIDDEN,
296
- connection_init="random",
294
+ connection_init=connection_init,
297
295
  )
298
296
 
299
297
 
@@ -0,0 +1,28 @@
1
+ # SPDX-License-Identifier: MIT
2
+
3
+ import numpy as np
4
+
5
+
6
+ def connection_init_value(mode: str) -> float | None:
7
+ """
8
+ Return an initial weight value for a new connection.
9
+
10
+ Args:
11
+ mode (str): Initialization mode. One of:
12
+ - "zero": weight = 0.0
13
+ - "near_zero": weight ~ U(-0.05, 0.05)
14
+ - "random": weight ~ N(0, 0.5)
15
+ - "none": no initialization (returns None)
16
+
17
+ Returns:
18
+ float | None: Initial connection weight or None.
19
+ """
20
+ if mode == "zero":
21
+ return 0.0
22
+ if mode == "near_zero":
23
+ return np.random.uniform(-0.05, 0.05)
24
+ if mode == "random":
25
+ return np.random.randn() * 0.5
26
+ if mode == "none":
27
+ return None
28
+ raise ValueError(f"Unknown connection_init mode: {mode}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evonet
3
- Version: 0.1.0.dev13
3
+ Version: 0.1.0.dev15
4
4
  Summary: Evolvable neural network core for integration with EvoLib
5
5
  Author-email: EvoLib <evolib@dismail.de>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "evonet"
7
- version = "0.1.0.dev13"
7
+ version = "0.1.0.dev15"
8
8
  description = "Evolvable neural network core for integration with EvoLib"
9
9
  authors = [
10
10
  { name = "EvoLib", email = "evolib@dismail.de" }
File without changes
File without changes
File without changes
File without changes
File without changes