evonet 0.1.0.dev15__tar.gz → 0.1.0.dev16__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 (27) hide show
  1. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/PKG-INFO +1 -1
  2. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/core.py +54 -23
  3. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet.egg-info/PKG-INFO +1 -1
  4. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/pyproject.toml +1 -1
  5. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/LICENSE +0 -0
  6. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/README.md +0 -0
  7. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/__init__.py +0 -0
  8. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/activation.py +0 -0
  9. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/connection.py +0 -0
  10. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/core_mit_plot_simple.py +0 -0
  11. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/enums.py +0 -0
  12. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/io.py +0 -0
  13. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/layer.py +0 -0
  14. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/mutation.py +0 -0
  15. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/neuron.py +0 -0
  16. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/serialization.py +0 -0
  17. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/utils.py +0 -0
  18. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet/visualize.py +0 -0
  19. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet.egg-info/SOURCES.txt +0 -0
  20. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet.egg-info/dependency_links.txt +0 -0
  21. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet.egg-info/requires.txt +0 -0
  22. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/evonet.egg-info/top_level.txt +0 -0
  23. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/setup.cfg +0 -0
  24. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/tests/test_activation.py +0 -0
  25. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/tests/test_core.py +0 -0
  26. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/tests/test_nnet_io_and_forward.py +0 -0
  27. {evonet-0.1.0.dev15 → evonet-0.1.0.dev16}/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.dev15
3
+ Version: 0.1.0.dev16
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,6 +9,7 @@ export interfaces.
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
+ import random
12
13
  from pathlib import Path
13
14
  from typing import Literal, Optional
14
15
 
@@ -105,6 +106,8 @@ class Nnet:
105
106
  count: int = 1,
106
107
  connection_init: Literal["random", "zero", "near_zero", "none"] = "zero",
107
108
  recurrent: Optional[set[RecurrentKind]] = None,
109
+ connection_scope: Literal["adjacent", "crosslayer"] = "adjacent",
110
+ connection_density: float = 1.0,
108
111
  ) -> list[Neuron]:
109
112
  """
110
113
  Add one or more neurons to the network.
@@ -122,6 +125,13 @@ class Nnet:
122
125
  "near_zero" - connect with small random weights (-0.05, 0.05)
123
126
  "none" - do not create connections (feedforward + recurrent)
124
127
  recurrent: Optional recurrent connection types.
128
+ connection_scope:
129
+ - "adjacent": only connect to directly neighboring layers (default)
130
+ - "crosslayer": connect to all earlier and later
131
+ layers (feedforward only)
132
+ connection_density:
133
+ Fraction of possible connections that should actually be created.
134
+ Must be in (0, 1]. A value <1.0 randomly samples a subset.
125
135
 
126
136
  Returns:
127
137
  list[Neuron]: List of added neurons.
@@ -129,11 +139,12 @@ class Nnet:
129
139
  if layer_idx is None:
130
140
  layer_idx = len(self.layers) - 1 # Add neuron to last layer
131
141
 
132
- if layer_idx < 0:
133
- raise ValueError(f"Layer index must be >= 0 (got {layer_idx})")
134
- if layer_idx >= len(self.layers):
142
+ if layer_idx < 0 or layer_idx >= len(self.layers):
135
143
  raise ValueError(f"Layer index out of bounds: {layer_idx}")
136
144
 
145
+ if not (0.0 < connection_density <= 1.0):
146
+ raise ValueError("connection_density must be in (0, 1].")
147
+
137
148
  target_layer = self.layers[layer_idx]
138
149
  new_neurons: list[Neuron] = []
139
150
 
@@ -145,29 +156,49 @@ class Nnet:
145
156
  target_layer.neurons.append(neuron)
146
157
  new_neurons.append(neuron)
147
158
 
148
- # Weights based on init mode
149
- weight = connection_init_value(connection_init)
150
-
151
- skip_connections = connection_init == "none"
159
+ # Skip connection creation if requested
160
+ if connection_init == "none":
161
+ return new_neurons
152
162
 
153
- # Connect to previous layer
154
- if not skip_connections and layer_idx > 0:
155
- for prev_neuron in self.layers[layer_idx - 1].neurons:
156
- for n in new_neurons:
157
- self.add_connection(prev_neuron, n, weight=weight)
158
-
159
- # Connect to next layer (hidden only)
160
- if (
161
- not skip_connections
162
- and role == NeuronRole.HIDDEN
163
- and layer_idx < len(self.layers) - 1
164
- ):
165
- for next_neuron in self.layers[layer_idx + 1].neurons:
166
- for n in new_neurons:
167
- self.add_connection(n, next_neuron, weight=weight)
163
+ weight = connection_init_value(connection_init)
164
+ possible_pairs: list[tuple[Neuron, Neuron]] = []
165
+
166
+ # Connection logic
167
+ if connection_scope == "adjacent":
168
+ # Previous layer ---> new neurons
169
+ if layer_idx > 0:
170
+ for src in self.layers[layer_idx - 1].neurons:
171
+ for n in new_neurons:
172
+ possible_pairs.append((src, n))
173
+ # New neurons ---> next layer (only for hidden neurons)
174
+ if role == NeuronRole.HIDDEN and layer_idx < len(self.layers) - 1:
175
+ for dst in self.layers[layer_idx + 1].neurons:
176
+ for n in new_neurons:
177
+ possible_pairs.append((n, dst))
178
+
179
+ elif connection_scope == "crosslayer":
180
+ # All earlier layers ---> new neurons
181
+ for i in range(0, layer_idx):
182
+ for src in self.layers[i].neurons:
183
+ for n in new_neurons:
184
+ possible_pairs.append((src, n))
185
+ # New neurons ---> all later layers
186
+ for j in range(layer_idx + 1, len(self.layers)):
187
+ for dst in self.layers[j].neurons:
188
+ for n in new_neurons:
189
+ possible_pairs.append((n, dst))
190
+
191
+ # Density control: subsample of possible pairs
192
+ if connection_density < 1.0 and possible_pairs:
193
+ k = max(1, int(len(possible_pairs) * connection_density))
194
+ possible_pairs = random.sample(possible_pairs, k)
195
+
196
+ # Create connections
197
+ for src, dst in possible_pairs:
198
+ self.add_connection(src, dst, weight=weight)
168
199
 
169
200
  # Recurrent connections
170
- if recurrent and not skip_connections:
201
+ if recurrent:
171
202
  if RecurrentKind.DIRECT in recurrent:
172
203
  for n in new_neurons:
173
204
  if n.role != NeuronRole.HIDDEN:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evonet
3
- Version: 0.1.0.dev15
3
+ Version: 0.1.0.dev16
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.dev15"
7
+ version = "0.1.0.dev16"
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