evonet 0.1.0.dev7__tar.gz → 0.1.0.dev8__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 (25) hide show
  1. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/PKG-INFO +1 -1
  2. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/core.py +45 -27
  3. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/mutation.py +2 -2
  4. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet.egg-info/PKG-INFO +1 -1
  5. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/pyproject.toml +1 -1
  6. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/tests/test_core.py +4 -4
  7. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/tests/test_nnet_io_and_forward.py +5 -5
  8. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/tests/test_recurrent_dynamics.py +3 -3
  9. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/LICENSE +0 -0
  10. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/README.md +0 -0
  11. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/__init__.py +0 -0
  12. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/activation.py +0 -0
  13. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/connection.py +0 -0
  14. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/enums.py +0 -0
  15. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/io.py +0 -0
  16. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/layer.py +0 -0
  17. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/neuron.py +0 -0
  18. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/utils.py +0 -0
  19. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet/visualize.py +0 -0
  20. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet.egg-info/SOURCES.txt +0 -0
  21. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet.egg-info/dependency_links.txt +0 -0
  22. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet.egg-info/requires.txt +0 -0
  23. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/evonet.egg-info/top_level.txt +0 -0
  24. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/setup.cfg +0 -0
  25. {evonet-0.1.0.dev7 → evonet-0.1.0.dev8}/tests/test_activation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evonet
3
- Version: 0.1.0.dev7
3
+ Version: 0.1.0.dev8
4
4
  Summary: Evolvable neural network core for integration with EvoLib
5
5
  Author-email: EvoLib <evolib@dismail.de>
6
6
  License: MIT License
@@ -9,7 +9,7 @@ export interfaces.
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
- from typing import Optional
12
+ from typing import Literal, Optional
13
13
 
14
14
  import graphviz
15
15
  import numpy as np
@@ -100,31 +100,33 @@ class Nnet:
100
100
  label: str = "",
101
101
  role: NeuronRole = NeuronRole.HIDDEN,
102
102
  count: int = 1,
103
- connect_layer: bool = True,
103
+ connection_init: Literal["random", "zero", "none"] = "random",
104
104
  recurrent: Optional[set[RecurrentKind]] = None,
105
105
  ) -> list[Neuron]:
106
106
  """
107
107
  Add one or more neurons to the network.
108
108
 
109
109
  Args:
110
- layer_idx (int | None): Target layer index. Defaults to last layer.
111
- activation (str): Activation function name.
112
- bias (float): Initial bias value.
113
- label (str): Optional label.
114
- role (NeuronRole): Role of the neuron (INPUT, HIDDEN, OUTPUT).
115
- count (int): Number of neurons to add (default: 1).
116
- connect_layer (bool): If True, auto-connect to adjacent layers.
117
- recurrent (set[RecurrentKind] | None): Optional recurrent connection types.
110
+ layer_idx: Target layer index. Defaults to last layer.
111
+ activation: Activation function name.
112
+ bias: Initial bias value.
113
+ label: Optional label.
114
+ role: Role of the neuron (INPUT, HIDDEN, OUTPUT).
115
+ count: Number of neurons to add (default: 1).
116
+ connection_init:
117
+ "random" connect with random weights (feedforward + recurrent)
118
+ "zero" – connect with weight 0.0 (feedforward + recurrent)
119
+ "none" – do not create connections (feedforward + recurrent)
120
+ recurrent: Optional recurrent connection types.
118
121
 
119
122
  Returns:
120
123
  list[Neuron]: List of added neurons.
121
124
  """
122
-
123
125
  if layer_idx is None:
124
126
  layer_idx = len(self.layers) - 1 # Add neuron to last layer
125
127
 
126
128
  if layer_idx < 0:
127
- raise ValueError(f"Expected positiv layerindex: got {layer_idx}")
129
+ raise ValueError(f"Layer index must be >= 0 (got {layer_idx})")
128
130
  if layer_idx >= len(self.layers):
129
131
  raise ValueError(f"Layer index out of bounds: {layer_idx}")
130
132
 
@@ -132,46 +134,56 @@ class Nnet:
132
134
  new_neurons: list[Neuron] = []
133
135
 
134
136
  # Create neurons without connections
135
- for i in range(count):
137
+ for _ in range(count):
136
138
  neuron = Neuron(activation=activation, bias=bias)
137
139
  neuron.role = role
138
140
  neuron.label = label
139
141
  target_layer.neurons.append(neuron)
140
142
  new_neurons.append(neuron)
141
143
 
142
- # Connect to previous layer (feedforward)
143
- if connect_layer and layer_idx > 0:
144
+ # Weights based on init mode
145
+ weight_map = {"random": None, "zero": 0.0, "none": None}
146
+ if connection_init not in weight_map:
147
+ raise ValueError(f"Invalid connection_init: {connection_init}")
148
+ weight = weight_map[connection_init]
149
+
150
+ skip_connections = connection_init == "none"
151
+
152
+ # Connect to previous layer
153
+ if not skip_connections and layer_idx > 0:
144
154
  for prev_neuron in self.layers[layer_idx - 1].neurons:
145
155
  for n in new_neurons:
146
- self.add_connection(prev_neuron, n)
156
+ self.add_connection(prev_neuron, n, weight=weight)
147
157
 
148
- # Connect to next layer (feedforward)
158
+ # Connect to next layer (hidden only)
149
159
  if (
150
- connect_layer
160
+ not skip_connections
151
161
  and role == NeuronRole.HIDDEN
152
162
  and layer_idx < len(self.layers) - 1
153
163
  ):
154
-
155
164
  for next_neuron in self.layers[layer_idx + 1].neurons:
156
165
  for n in new_neurons:
157
- self.add_connection(n, next_neuron)
166
+ self.add_connection(n, next_neuron, weight=weight)
158
167
 
159
168
  # Recurrent connections
160
- if recurrent:
169
+ if recurrent and not skip_connections:
161
170
  if RecurrentKind.DIRECT in recurrent:
162
171
  for n in new_neurons:
163
172
  if n.role == NeuronRole.HIDDEN:
164
- self.add_connection(n, n, conn_type=ConnectionType.RECURRENT)
173
+ self.add_connection(
174
+ n, n, weight=weight, conn_type=ConnectionType.RECURRENT
175
+ )
165
176
 
166
177
  if RecurrentKind.LATERAL in recurrent:
167
- # All neurons in this layer (old + new)
168
178
  full_layer = list(self.layers[layer_idx].neurons)
169
-
170
179
  for src in full_layer:
171
180
  for dst in new_neurons:
172
181
  if src is not dst:
173
182
  self.add_connection(
174
- src, dst, conn_type=ConnectionType.RECURRENT
183
+ src,
184
+ dst,
185
+ weight=weight,
186
+ conn_type=ConnectionType.RECURRENT,
175
187
  )
176
188
 
177
189
  if RecurrentKind.INDIRECT in recurrent:
@@ -179,13 +191,19 @@ class Nnet:
179
191
  for lower_layer in self.layers[1:layer_idx]:
180
192
  for dst in lower_layer.neurons:
181
193
  self.add_connection(
182
- src, dst, conn_type=ConnectionType.RECURRENT
194
+ src,
195
+ dst,
196
+ weight=weight,
197
+ conn_type=ConnectionType.RECURRENT,
183
198
  )
184
199
  for higher_layer in self.layers[layer_idx + 1 :]:
185
200
  for src in higher_layer.neurons:
186
201
  for dst in new_neurons:
187
202
  self.add_connection(
188
- src, dst, conn_type=ConnectionType.RECURRENT
203
+ src,
204
+ dst,
205
+ weight=weight,
206
+ conn_type=ConnectionType.RECURRENT,
189
207
  )
190
208
 
191
209
  return new_neurons
@@ -270,7 +270,7 @@ def add_random_neuron(net: Nnet, activations: list[str] | None = None) -> None:
270
270
  layer_idx=net.layers.index(layer),
271
271
  activation=random_function_name(activations),
272
272
  role=NeuronRole.HIDDEN,
273
- connect_layer=True,
273
+ connection_init="random",
274
274
  )
275
275
 
276
276
 
@@ -332,7 +332,7 @@ def split_connection(net: Nnet, activation: str = "tanh", noise: float = 0.1) ->
332
332
  layer_idx=insert_idx,
333
333
  role=NeuronRole.HIDDEN,
334
334
  activation=activation,
335
- connect_layer=False,
335
+ connection_init="none",
336
336
  )[0]
337
337
 
338
338
  # Set new connections
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evonet
3
- Version: 0.1.0.dev7
3
+ Version: 0.1.0.dev8
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.dev7"
7
+ version = "0.1.0.dev8"
8
8
  description = "Evolvable neural network core for integration with EvoLib"
9
9
  authors = [
10
10
  { name = "EvoLib", email = "evolib@dismail.de" }
@@ -13,14 +13,14 @@ def test_forward_pass_identity() -> None:
13
13
  activation="linear",
14
14
  role=NeuronRole.INPUT,
15
15
  label="in",
16
- connect_layer=False,
16
+ connection_init="none",
17
17
  )
18
18
  net.add_neuron(
19
19
  layer_idx=1,
20
20
  activation="linear",
21
21
  role=NeuronRole.OUTPUT,
22
22
  label="out",
23
- connect_layer=False,
23
+ connection_init="none",
24
24
  )
25
25
 
26
26
  src = net.layers[0].neurons[0]
@@ -49,7 +49,7 @@ def test_forward_pass_with_bias() -> None:
49
49
  activation="linear",
50
50
  role=NeuronRole.INPUT,
51
51
  label="in",
52
- connect_layer=False,
52
+ connection_init="none",
53
53
  )
54
54
  net.add_neuron(
55
55
  layer_idx=1,
@@ -57,7 +57,7 @@ def test_forward_pass_with_bias() -> None:
57
57
  role=NeuronRole.OUTPUT,
58
58
  bias=0.5,
59
59
  label="out",
60
- connect_layer=False,
60
+ connection_init="none",
61
61
  )
62
62
 
63
63
  src = net.layers[0].neurons[0]
@@ -29,21 +29,21 @@ def build_simple_ff_net() -> Nnet:
29
29
  role=NeuronRole.INPUT,
30
30
  activation="linear",
31
31
  count=2,
32
- connect_layer=False,
32
+ connection_init="none",
33
33
  )
34
34
  net.add_neuron(
35
35
  layer_idx=1,
36
36
  role=NeuronRole.HIDDEN,
37
37
  activation="linear",
38
38
  count=3,
39
- connect_layer=True,
39
+ connection_init="random",
40
40
  )
41
41
  net.add_neuron(
42
42
  layer_idx=2,
43
43
  role=NeuronRole.OUTPUT,
44
44
  activation="linear",
45
45
  count=1,
46
- connect_layer=True,
46
+ connection_init="random",
47
47
  )
48
48
  return net
49
49
 
@@ -117,14 +117,14 @@ def test_forward_sanity_linear_1x1() -> None:
117
117
  role=NeuronRole.INPUT,
118
118
  activation="linear",
119
119
  count=1,
120
- connect_layer=False,
120
+ connection_init="none",
121
121
  )
122
122
  net.add_neuron(
123
123
  layer_idx=1,
124
124
  role=NeuronRole.OUTPUT,
125
125
  activation="linear",
126
126
  count=1,
127
- connect_layer=True,
127
+ connection_init="random",
128
128
  )
129
129
 
130
130
  # There should be exactly one connection L0(0) -> L1(0). Force known params:
@@ -15,17 +15,17 @@ def _mk_linear_ih_h_o() -> tuple[Nnet, Neuron, Neuron, Neuron]:
15
15
  net.add_layer(3) # input, hidden, output
16
16
 
17
17
  neurons: list[Neuron] = net.add_neuron(
18
- layer_idx=0, role=NeuronRole.INPUT, activation="linear", connect_layer=False
18
+ layer_idx=0, role=NeuronRole.INPUT, activation="linear", connection_init="none"
19
19
  )
20
20
  n_in = neurons[0]
21
21
 
22
22
  neurons = net.add_neuron(
23
- layer_idx=1, role=NeuronRole.HIDDEN, activation="linear", connect_layer=False
23
+ layer_idx=1, role=NeuronRole.HIDDEN, activation="linear", connection_init="none"
24
24
  )
25
25
  n_hid = neurons[0]
26
26
 
27
27
  neurons = net.add_neuron(
28
- layer_idx=2, role=NeuronRole.OUTPUT, activation="linear", connect_layer=False
28
+ layer_idx=2, role=NeuronRole.OUTPUT, activation="linear", connection_init="none"
29
29
  )
30
30
  n_out = neurons[0]
31
31
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes