evolib 0.2.0b4.dev8__tar.gz → 0.2.0b4.dev10__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 (157) hide show
  1. {evolib-0.2.0b4.dev8/evolib.egg-info → evolib-0.2.0b4.dev10}/PKG-INFO +1 -1
  2. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/config_guide.md +16 -4
  3. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/config_parameter.md +30 -14
  4. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/config/base_component_config.py +41 -16
  5. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/config/evonet_component_config.py +76 -69
  6. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/config/vector_component_config.py +40 -9
  7. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/initializers/evonet_initializers.py +2 -3
  8. evolib-0.2.0b4.dev10/evolib/initializers/registry.py +112 -0
  9. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/interfaces/enums.py +1 -2
  10. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/evonet_structural_mutation.py +1 -2
  11. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/selection.py +12 -7
  12. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/evonet.py +5 -3
  13. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10/evolib.egg-info}/PKG-INFO +1 -1
  14. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib.egg-info/SOURCES.txt +0 -1
  15. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/02_strategies/01_step_by_step_evolution.py +2 -2
  16. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/05_advanced_topics/06_evolving_mutation_strength_as_a_module.py +1 -1
  17. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/03_delay_bitseq_echo.py +1 -1
  18. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/05_image_approximation.py +1 -2
  19. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/pyproject.toml +1 -1
  20. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_config_loader.py +1 -1
  21. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_evonet_neuron_dynamics.py +10 -4
  22. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_initializer_evonet.py +6 -2
  23. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_initializer_net.py +3 -3
  24. evolib-0.2.0b4.dev8/evolib/initializers/registry.py +0 -85
  25. evolib-0.2.0b4.dev8/evolib/interfaces/enum_helpers.py +0 -31
  26. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/LICENSE +0 -0
  27. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/MANIFEST.in +0 -0
  28. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/README.md +0 -0
  29. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_core_individual.rst +0 -0
  30. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_core_population.rst +0 -0
  31. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_operators_crossover.rst +0 -0
  32. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_operators_evonet_structural_mutation.rst +0 -0
  33. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_operators_mutation.rst +0 -0
  34. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_operators_replacement.rst +0 -0
  35. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_operators_reproduction.rst +0 -0
  36. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_operators_selection.rst +0 -0
  37. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_operators_strategy.rst +0 -0
  38. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_public_api.rst +0 -0
  39. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_representation_evonet.rst +0 -0
  40. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_representation_netvector.rst +0 -0
  41. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_representation_vector.rst +0 -0
  42. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_utils_benchmarks.rst +0 -0
  43. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_utils_history_logger.rst +0 -0
  44. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_utils_loss_functions.rst +0 -0
  45. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/api_utils_plotting.rst +0 -0
  46. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/conf.py +0 -0
  47. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/getting_started.md +0 -0
  48. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/docs/index.md +0 -0
  49. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/__init__.py +0 -0
  50. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/api.py +0 -0
  51. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/config/__init__.py +0 -0
  52. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/config/component_registry.py +0 -0
  53. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/config/schema.py +0 -0
  54. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/core/README.md +0 -0
  55. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/core/__init__.py +0 -0
  56. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/core/individual.py +0 -0
  57. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/core/population.py +0 -0
  58. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/envs/gym_wrapper.py +0 -0
  59. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/globals/README.md +0 -0
  60. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/globals/__init__.py +0 -0
  61. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/globals/numeric.py +0 -0
  62. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/initializers/__init__.py +0 -0
  63. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/initializers/net_initializers.py +0 -0
  64. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/initializers/vector_initializers.py +0 -0
  65. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/interfaces/__init__.py +0 -0
  66. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/interfaces/structs.py +0 -0
  67. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/interfaces/types.py +0 -0
  68. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/io/checkpoint.py +0 -0
  69. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/io/serialization.py +0 -0
  70. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/README.md +0 -0
  71. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/__init__.py +0 -0
  72. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/crossover.py +0 -0
  73. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/heli.py +0 -0
  74. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/mutation.py +0 -0
  75. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/replacement.py +0 -0
  76. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/reproduction.py +0 -0
  77. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/operators/strategy.py +0 -0
  78. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/registry/__init__.py +0 -0
  79. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/registry/replacement_registry.py +0 -0
  80. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/registry/selection_registry.py +0 -0
  81. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/registry/strategy_registry.py +0 -0
  82. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/__init__.py +0 -0
  83. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/_apply_config_mapping.py +0 -0
  84. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/base.py +0 -0
  85. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/composite.py +0 -0
  86. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/dummy.py +0 -0
  87. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/evo_params.py +0 -0
  88. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/netvector.py +0 -0
  89. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/representation/vector.py +0 -0
  90. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/README.md +0 -0
  91. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/__init__.py +0 -0
  92. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/benchmarks.py +0 -0
  93. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/config_loader.py +0 -0
  94. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/fitness.py +0 -0
  95. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/heli_experiment_logger.py +0 -0
  96. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/heli_utils.py +0 -0
  97. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/history_logger.py +0 -0
  98. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/lineage_logger.py +0 -0
  99. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/loss_functions.py +0 -0
  100. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/parallel.py +0 -0
  101. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/plotting.py +0 -0
  102. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/random.py +0 -0
  103. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib/utils/registry.py +0 -0
  104. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib.egg-info/dependency_links.txt +0 -0
  105. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib.egg-info/requires.txt +0 -0
  106. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/evolib.egg-info/top_level.txt +0 -0
  107. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/01_basic_usage/01_getting_started.py +0 -0
  108. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/01_basic_usage/02_mutation.py +0 -0
  109. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/01_basic_usage/03_population_mutation.py +0 -0
  110. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/01_basic_usage/04_fitness.py +0 -0
  111. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/02_strategies/02_mu_lambda_step.py +0 -0
  112. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/02_strategies/03_mu_lambda.py +0 -0
  113. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/02_strategies/04_flexible.py +0 -0
  114. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/01_history.py +0 -0
  115. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/02_plotting.py +0 -0
  116. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/03_compare_runs.py +0 -0
  117. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/04_exponential_decay_vs_static.py +0 -0
  118. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/05_adaptive_global_vs_static.py +0 -0
  119. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/06_adaptive_individual_vs_static.py +0 -0
  120. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/07_selection_comparison.py +0 -0
  121. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/08_selection_pressure.py +0 -0
  122. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/09_selection_vs_mutation_pressure.py +0 -0
  123. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/10_selection_stochastic_vs_deterministic.py +0 -0
  124. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/03_comparisons/11_crossover_comparison.py +0 -0
  125. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/04_function_approximation/01_polynomial_sine.py +0 -0
  126. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/04_function_approximation/02_sine_point_approximation.py +0 -0
  127. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/04_function_approximation/03_approximation_with_noise.py +0 -0
  128. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/05_advanced_topics/01_fitness_landscape_exploration.py +0 -0
  129. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/05_advanced_topics/02_rosenbrock_surface_path.py +0 -0
  130. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/05_advanced_topics/03_vector_control.py +0 -0
  131. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/05_advanced_topics/04_vector_control_with_obstacles.py +0 -0
  132. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/05_advanced_topics/05_piecewise_linear_xsys.py +0 -0
  133. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/06_netvector/01_netvector_sine_approximation.py +0 -0
  134. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/06_netvector/02_netvector_modulated_output.py +0 -0
  135. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/06_netvector/03_netvector_gain_and_bias.py +0 -0
  136. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/01_sine_approximation.py +0 -0
  137. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/02_sine_delay.py +0 -0
  138. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/04_leaky_temporal_smoothing.py +0 -0
  139. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/06_structural_xor.py +0 -0
  140. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/07_recurrent_bit_prediction.py +0 -0
  141. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/08_recurrent_timeseries.py +0 -0
  142. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/07_evonet/09_recurrent_trading.py +0 -0
  143. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/08_gym/01_frozen_lake.py +0 -0
  144. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/08_gym/02_cliff_walking.py +0 -0
  145. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/08_gym/03_cartpole.py +0 -0
  146. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/08_gym/04_lunar_lander.py +0 -0
  147. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/08_gym/05_bipedal_walker.py +0 -0
  148. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/09_meta_learning/01_lamarck_linear_mapping.py +0 -0
  149. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/examples/09_meta_learning/02_meta_mapping_baldwin.py +0 -0
  150. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/setup.cfg +0 -0
  151. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_benchmarks.py +0 -0
  152. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_elitism_preserves_best_fitness.py +0 -0
  153. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_evonet_deepcopy.py +0 -0
  154. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_evonet_vector_io.py +0 -0
  155. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_mutation.py +0 -0
  156. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_population.py +0 -0
  157. {evolib-0.2.0b4.dev8 → evolib-0.2.0b4.dev10}/tests/test_selection.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evolib
3
- Version: 0.2.0b4.dev8
3
+ Version: 0.2.0b4.dev10
4
4
  Summary: A modular framework for evolutionary strategies and neuroevolution.
5
5
  Author-email: EvoLib <evolib@dismail.de>
6
6
  License: MIT License
@@ -30,7 +30,7 @@ evolution:
30
30
  modules:
31
31
  test-vector: # logical module name
32
32
  type: vector
33
- initializer: random_vector
33
+ initializer: uniform
34
34
  dim: 2
35
35
  bounds: [-1.0, 1.0]
36
36
 
@@ -89,7 +89,7 @@ modules:
89
89
  xs:
90
90
  type: vector
91
91
  dim: 6
92
- initializer: random_vector
92
+ initializer: uniform
93
93
  bounds: [0.0, 6.283185307] # [0, 2π]
94
94
  mutation:
95
95
  strategy: adaptive_individual
@@ -120,6 +120,11 @@ This configuration demonstrates EvoNet evolution: weight mutation, bias-specific
120
120
 
121
121
  `dim: [2, 0, 0, 1]` starts with empty hidden layers, letting structural mutation grow nodes and edges.
122
122
 
123
+ Connectivity:
124
+ - `scope` controls which feedforward edges are allowed at initialization.
125
+ - `density` controls how many of those allowed edges are actually created at init.
126
+ - `recurrent` enables recurrent edge kinds (empty list means none).
127
+
123
128
  Topology constraints:
124
129
  - `max_neurons` and `max_connections` keep growth bounded (these are the current names; avoid older `max_nodes/max_edges`).
125
130
 
@@ -127,6 +132,8 @@ Delay:
127
132
  - `delay:` initializes delays of recurrent connections at build time.
128
133
  - `mutation.delay:` mutates delays during evolution (recurrent connections only).
129
134
 
135
+
136
+
130
137
  ```yaml
131
138
  parent_pool_size: 20
132
139
  offspring_pool_size: 40
@@ -145,17 +152,22 @@ modules:
145
152
  type: evonet
146
153
  dim: [2, 0, 0, 1] # hidden layers start empty
147
154
  activation: [linear, tanh, tanh, sigmoid]
155
+
156
+ connectivity:
157
+ scope: crosslayer # adjacent | crosslayer
158
+ density: 1.0 # (0, 1]
159
+ recurrent: [direct] # [], [direct], [lateral], [indirect]
160
+
148
161
  weights:
149
162
  initializer: normal
150
163
  std: 0.5
151
164
  bounds: [-5.0, 5.0]
165
+
152
166
  bias:
153
167
  initializer: normal
154
168
  std: 0.5
155
169
  bounds: [-1.0, 1.0]
156
170
 
157
- recurrent: direct # REQUIRED for delay to have any effect
158
-
159
171
  # NOTE: Delays only apply to recurrent connections.
160
172
  # If `recurrent` is not enabled, this block has no effect.
161
173
  delay:
@@ -152,7 +152,7 @@ The `vector` module defines an evolvable parameter vector.
152
152
  | `type` | `"vector"` | — | Module type identifier. |
153
153
  | `dim` | `int \| list[int]` | — | Vector length (`int`) or structured dimensions (`list[int]`). Must be > 0. |
154
154
  | `structure` | `"flat" \| "net" | `"flat"` | Structural interpretation of the vector. |
155
- | `initializer` | `str` | — | Initializer name from the registry (e.g. `random_vector`, `zero_vector`, `normal_vector`, `fixed_vector`). |
155
+ | `initializer` | `str` | — | Initializer name from the registry (e.g. `uniform`, `zero`, `normal`, `fixed`). |
156
156
  | `bounds` | `tuple[float, float]` | `[-1.0, 1.0]` | Hard clamp range applied after mutation. |
157
157
  | `init_bounds` | `tuple[float, float] \| null` | `null` | Clamp applied only during initialization. Falls back to `bounds` if not set. |
158
158
  | `shape` | `tuple[int, ...] \| null` | `null` | Optional explicit shape. If set, `dim = product(shape)`. Shape is retained as metadata. |
@@ -232,7 +232,7 @@ modules:
232
232
  main:
233
233
  type: vector
234
234
  dim: 8
235
- initializer: random_vector
235
+ initializer: uniform
236
236
  bounds: [-1.0, 1.0]
237
237
 
238
238
  mutation:
@@ -288,13 +288,31 @@ modules:
288
288
  |-------------------|---------------------|---------|-------------|
289
289
  | `dim` | list[int] | — | Layer sizes, e.g. `[4, 0, 0, 2]`. Hidden layers can start empty (0) and grow through structural mutation. |
290
290
  | `activation` | str \| list[str] | — | If list: activation per layer. If str: used for non-input layers; input layer is treated as linear. |
291
- | `initializer` | str | default_evonet | Topology preset (e.g. `default_evonet`, `unconnected_evonet`, `identity_evonet`). Parameter initialization is configured via `weights`, `bias`, and `delay`. |
291
+ | `initializer` | str | default | Topology preset (e.g. `default`, `unconnected`, `identity`). Parameter initialization is configured via `weights`, `bias`, and `delay`. |
292
+ | `connectivity` | `dict` | — | **Required.** Defines feedforward scope/density and allowed recurrent kinds. |
292
293
  | `weights` | dict | — | Weight init and bounds configuration (initializer, bounds, optional params). |
293
294
  | `bias` | dict | — | Bias init and bounds configuration (initializer, bounds, optional params). |
294
295
  | `neuron_dynamics` | list[dict] \| null | null | Optional per-layer neuron dynamics specification. Must match `len(dim)`. |
295
296
  | `mutation` | dict \| null | null | Mutation settings for weights, biases, activations, delay, and structure. |
296
297
  | `crossover` | dict \| null | null | Optional crossover settings (weight/bias level). |
297
298
 
299
+ #### Connectivity (`connectivity`)
300
+
301
+ | Field | Type | Default | Notes |
302
+ |------------|------------------------------|---------|------|
303
+ | `scope` | `"adjacent" \| "crosslayer"` | — | **Required.** Allowed feedforward edge scope at initialization. |
304
+ | `density` | `float` | — | **Required.** Fraction of allowed feedforward edges created at init `(0,1]`. |
305
+ | `recurrent`| `list[str]` | `[]` | Allowed recurrent edge kinds. Empty list means none. |
306
+
307
+ Example:
308
+
309
+ ```yaml
310
+ connectivity:
311
+ scope: crosslayer
312
+ density: 0.5
313
+ recurrent: [direct]
314
+ ```
315
+
298
316
  ##### weights block
299
317
  |Parameter | Type | Default | Explanation |
300
318
  |------------|-------|-----------|-------------|
@@ -324,9 +342,9 @@ Allowed presets:
324
342
 
325
343
  | Initializer | Meaning (topology only) |
326
344
  |------------------------|-------------------------|
327
- | `default_evonet` | Standard EvoNet topology preset (uses `connection_scope`, `connection_density`, and `recurrent`). |
328
- | `unconnected_evonet` | Creates neurons/layers but starts with **no connections** (use structural mutation to grow). |
329
- | `identity_evonet` | Special preset intended for stable recurrent memory (may override parameters internally; see notes below). |
345
+ | `default` | Standard EvoNet topology preset (uses `connection_scope`, `connection_density`, and `recurrent`). |
346
+ | `unconnected` | Creates neurons/layers but starts with **no connections** (use structural mutation to grow). |
347
+ | `identity` | Special preset intended for stable recurrent memory (may override parameters internally; see notes below). |
330
348
 
331
349
  ---
332
350
 
@@ -493,13 +511,12 @@ structural:
493
511
 
494
512
  ### Topology constraints
495
513
 
496
- | Field | Type | Default | Description |
497
- |---------------------|---------------|----------|-------------|
498
- | `recurrent` | str | `none` | Controls recurrence: `none`, `direct`, `local` or `all`. |
499
- | `connection_scope` | str | `adjacent` | Allowed layer connectivity: `adjacent` (neighbor layers only) or `crosslayer` (any-to-any). |
500
- | `connection_density` | float | 1.0 | Fraction of possible connections initialized at creation time. |
501
- | `max_neurons` | int \| null | null | Maximum number of non-input neurons (`null` = unlimited). |
502
- | `max_connections` | int \| null | null | Maximum number of edges (`null` = unlimited). |
514
+ | Field | Type | Default | Description |
515
+ |-------------------|--------------------------------|-------------|-------------|
516
+ | `recurrent` | `list[str]` | `[]` | Allowed recurrent kinds for `add_connection`. Empty list means none. |
517
+ | `connection_scope` | `"adjacent" \| "crosslayer" \| null` | `"adjacent"` | Constraint for structural add-neuron / add-connection edge placement. |
518
+ | `max_neurons` | `int \| null` | `null` | Upper bound on total neurons allowed (implementation-defined counting). |
519
+ | `max_connections` | `int \| null` | `null` | Upper bound on total connections allowed. |
503
520
 
504
521
  ---
505
522
 
@@ -544,7 +561,6 @@ modules:
544
561
  type: evonet
545
562
  dim: [4, 0, 0, 2]
546
563
  activation: [linear, tanh, tanh, tanh]
547
- initializer: normal_evonet
548
564
 
549
565
  delay:
550
566
  initializer: uniform
@@ -8,10 +8,11 @@ should be configured, not *how* it is executed. Any runtime behavior belongs
8
8
  into the respective Para* representations and operator modules.
9
9
  """
10
10
 
11
- from typing import Literal, Optional, Union
11
+ from typing import Any, Literal, Optional, Union
12
12
 
13
13
  from evonet.activation import ACTIVATIONS
14
- from pydantic import BaseModel, ConfigDict, Field, model_validator, validator
14
+ from evonet.enums import RecurrentKind
15
+ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
15
16
 
16
17
  from evolib.interfaces.enums import (
17
18
  CrossoverOperator,
@@ -221,15 +222,21 @@ class AddNeuron(BaseModel):
221
222
  "neurons in hidden layers.",
222
223
  )
223
224
 
224
- @validator("activations_allowed", each_item=True)
225
- def validate_activation_name(cls, act_name: str) -> str:
225
+ @field_validator("activations_allowed")
226
+ @classmethod
227
+ def validate_activations_allowed(
228
+ cls, acts: Optional[list[str]]
229
+ ) -> Optional[list[str]]:
226
230
  """Ensure only valid activation function names are allowed."""
227
- if act_name not in ACTIVATIONS:
228
- raise ValueError(
229
- f"Invalid activation function '{act_name}'. "
230
- f"Valid options are: {list(ACTIVATIONS.keys())}"
231
- )
232
- return act_name
231
+ if acts is None:
232
+ return None
233
+ for a in acts:
234
+ if a not in ACTIVATIONS:
235
+ raise ValueError(
236
+ f"Invalid activation function '{a}'. "
237
+ f"Valid options are: {sorted(ACTIVATIONS.keys())}"
238
+ )
239
+ return acts
233
240
 
234
241
 
235
242
  class RemoveNeuron(BaseModel):
@@ -267,7 +274,12 @@ class StructuralTopology(BaseModel):
267
274
  mutation operators.
268
275
  """
269
276
 
270
- recurrent: Optional[Literal["none", "direct", "local", "all"]] = "none"
277
+ recurrent: list[RecurrentKind] = Field(
278
+ default_factory=list,
279
+ description="Allowed recurrent edge kinds for structural "
280
+ "add_connection. Empty means none.",
281
+ )
282
+
271
283
  connection_scope: Optional[Literal["adjacent", "crosslayer"]] = "adjacent"
272
284
 
273
285
  max_neurons: Optional[int] = Field(
@@ -282,21 +294,34 @@ class StructuralTopology(BaseModel):
282
294
  ge=1,
283
295
  )
284
296
 
297
+ @field_validator("recurrent", mode="before")
298
+ @classmethod
299
+ def normalize_recurrent(cls, v: Any) -> list[RecurrentKind]:
300
+ """
301
+ Allow YAML convenience values like:
302
+ recurrent: none
303
+ recurrent: []
304
+ """
305
+ if v is None:
306
+ return []
307
+ if isinstance(v, str):
308
+ if v.lower() == "none":
309
+ return []
310
+ return [v]
311
+ return v
312
+
285
313
  @model_validator(mode="after")
286
314
  def _validate_topology(self) -> "StructuralTopology":
287
- if self.recurrent not in {None, "none", "direct", "local", "all"}:
288
- raise ValueError(f"Invalid recurrent value: {self.recurrent}")
289
-
290
315
  if self.connection_scope not in {None, "adjacent", "crosslayer"}:
291
316
  raise ValueError(f"Invalid connection_scope: {self.connection_scope}")
292
317
 
293
- # Only positive limits allowed
294
318
  if self.max_connections is not None and self.max_connections <= 0:
295
319
  raise ValueError("max_connections must be > 0")
296
-
297
320
  if self.max_neurons is not None and self.max_neurons <= 0:
298
321
  raise ValueError("max_neurons must be > 0")
299
322
 
323
+ # ensure deterministic unique list
324
+ self.recurrent = sorted(set(self.recurrent), key=lambda x: x.value)
300
325
  return self
301
326
 
302
327
 
@@ -11,16 +11,16 @@ After parsing, raw dicts are converted into this strongly typed Pydantic model d
11
11
  config resolution.
12
12
  """
13
13
 
14
- from typing import Literal, Optional, Tuple, Union
14
+ from typing import Any, Literal, Optional, Tuple, Union
15
15
 
16
16
  from evonet.activation import ACTIVATIONS
17
+ from evonet.enums import RecurrentKind
17
18
  from pydantic import (
18
19
  BaseModel,
19
20
  ConfigDict,
20
21
  Field,
21
22
  field_validator,
22
23
  model_validator,
23
- validator,
24
24
  )
25
25
  from pydantic_core import core_schema
26
26
 
@@ -30,10 +30,60 @@ from evolib.config.base_component_config import (
30
30
  EvoNetNeuronDynamicsConfig,
31
31
  StructuralMutationConfig,
32
32
  )
33
+ from evolib.interfaces.enums import RepresentationType
33
34
 
34
35
  Bounds = Tuple[float, float]
35
36
 
36
37
 
38
+ class ConnectivityConfig(BaseModel):
39
+ """
40
+ EvoNet connectivity configuration.
41
+
42
+ recurrent:
43
+ Allowed recurrent edge kinds (DIRECT/LATERAL/INDIRECT).
44
+ If omitted, no recurrent edges are allowed.
45
+
46
+ scope:
47
+ adjacent -> only adjacent-layer feedforward connections during init
48
+ crosslayer -> cross-layer feedforward connections during init
49
+
50
+ density:
51
+ Fraction of allowed feedforward edges to create at init (0 < density <= 1).
52
+ """
53
+
54
+ model_config = ConfigDict(extra="forbid")
55
+
56
+ recurrent: list[RecurrentKind] = Field(default_factory=list)
57
+
58
+ # Required: must be explicitly set in YAML
59
+ scope: Literal["adjacent", "crosslayer"]
60
+
61
+ # Required: must be explicitly set in YAML
62
+ density: float = Field(..., gt=0.0, le=1.0)
63
+
64
+ @field_validator("recurrent", mode="before")
65
+ @classmethod
66
+ def normalize_recurrent(cls, v: Any) -> list[RecurrentKind]:
67
+ """
68
+ Allow YAML convenience values like:
69
+ recurrent: none
70
+ recurrent: []
71
+ """
72
+ if v is None:
73
+ return []
74
+ if isinstance(v, str):
75
+ if v.lower() == "none":
76
+ return []
77
+ return [v]
78
+ return v
79
+
80
+ @model_validator(mode="after")
81
+ def _normalize(self) -> "ConnectivityConfig":
82
+ # deterministic, unique
83
+ self.recurrent = sorted(set(self.recurrent), key=lambda x: x.value)
84
+ return self
85
+
86
+
37
87
  class WeightsConfig(BaseModel):
38
88
  # None means: no parameter-level initialization requested (preset may initialize).
39
89
  initializer: Optional[str] = None # normal | uniform | zero | None
@@ -208,7 +258,10 @@ class EvoNetComponentConfig(BaseModel):
208
258
  model_config = ConfigDict(extra="forbid")
209
259
 
210
260
  # Module type is fixed to "evonet"
211
- type: Literal["evonet"] = "evonet"
261
+ type: RepresentationType = Field(
262
+ default=RepresentationType.EVONET,
263
+ description='Fixed module discriminator; must be "evonet" for this schema.',
264
+ )
212
265
 
213
266
  # Layer structure: list of neuron counts per layer [input, hidden..., output]
214
267
  dim: list[int]
@@ -223,33 +276,13 @@ class EvoNetComponentConfig(BaseModel):
223
276
  "neurons in hidden layers.",
224
277
  )
225
278
 
226
- # Recurrent connections
227
- recurrent: Optional[Literal["none", "direct", "local", "all"]] = "none"
228
-
229
279
  # Name of the initializer function (resolved via initializer registry)
230
280
  initializer: str = Field(
231
- default="default_evonet", description="Name of the initializer to use"
281
+ default="default", description="Name of the initializer to use"
232
282
  )
233
283
 
234
- # Connection topology for initialization
235
- connection_scope: Literal["adjacent", "crosslayer"] = Field(
236
- default="adjacent",
237
- description=(
238
- "Defines how layers are connected during initialization. "
239
- "'adjacent' connects only consecutive layers, while 'crosslayer' "
240
- "connects all earlier layers to all later layers."
241
- ),
242
- )
243
-
244
- connection_density: float = Field(
245
- default=1.0,
246
- ge=0.0,
247
- le=1.0,
248
- description=(
249
- "Fraction of possible connections actually created during initialization. "
250
- "1.0 = fully connected, <1.0 = sparse."
251
- ),
252
- )
284
+ # Connectivity
285
+ connectivity: ConnectivityConfig
253
286
 
254
287
  # Numeric bounds for values; used by initialization and mutation
255
288
  weights: WeightsConfig = Field(default_factory=WeightsConfig)
@@ -276,9 +309,9 @@ class EvoNetComponentConfig(BaseModel):
276
309
  Parameter initialization is handled exclusively via weights/bias/delay blocks.
277
310
  """
278
311
  allowed = {
279
- "default_evonet",
280
- "unconnected_evonet",
281
- "identity_evonet",
312
+ "default",
313
+ "unconnected",
314
+ "identity",
282
315
  }
283
316
 
284
317
  if name not in allowed:
@@ -331,45 +364,19 @@ class EvoNetComponentConfig(BaseModel):
331
364
  raise ValueError("Length of 'activation' list must match 'dim'")
332
365
  return act
333
366
 
334
- @validator("activations_allowed", each_item=True)
335
- def validate_activation_name(cls, act_name: str) -> str:
336
- """Ensure only valid activation function names are allowed."""
337
- if act_name not in ACTIVATIONS:
338
- raise ValueError(
339
- f"Invalid activation function '{act_name}'. "
340
- f"Valid options are: {list(ACTIVATIONS.keys())}"
341
- )
342
- return act_name
343
-
344
- @validator("recurrent")
345
- def validate_recurrent(cls, recurrent: Optional[str]) -> str:
346
- """Ensure recurrent preset is valid and normalized."""
347
- if recurrent is None:
348
- return "none"
349
- allowed = {"none", "direct", "local", "all"}
350
- if recurrent not in allowed:
351
- raise ValueError(
352
- f"Invalid recurrent preset '{recurrent}'. "
353
- f"Valid options are: {sorted(allowed)}"
354
- )
355
- return recurrent
356
-
357
- @field_validator("connection_scope")
367
+ @field_validator("activations_allowed")
358
368
  @classmethod
359
- def validate_connection_scope(cls, scope: str) -> str:
360
- """Ensure connection_scope is one of the supported options."""
361
- allowed = {"adjacent", "crosslayer"}
362
- if scope not in allowed:
363
- raise ValueError(
364
- f"Invalid connection_scope '{scope}'. "
365
- f"Valid options are: {sorted(allowed)}"
366
- )
367
- return scope
369
+ def validate_activations_allowed(
370
+ cls, acts: Optional[list[str]]
371
+ ) -> Optional[list[str]]:
372
+ """Validate that all activation names are known."""
373
+ if acts is None:
374
+ return None
368
375
 
369
- @field_validator("connection_density")
370
- @classmethod
371
- def validate_connection_density(cls, density: float) -> float:
372
- """Ensure connection_density is within [0, 1]."""
373
- if not (0.0 <= density <= 1.0):
374
- raise ValueError(f"connection_density must be in [0, 1], got {density}.")
375
- return density
376
+ for a in acts:
377
+ if a not in ACTIVATIONS:
378
+ raise ValueError(
379
+ f"Invalid activation function '{a}'. "
380
+ f"Valid options are: {sorted(ACTIVATIONS.keys())}"
381
+ )
382
+ return acts
@@ -1,7 +1,14 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  from typing import Any, Literal, Optional, Tuple, Union
3
3
 
4
- from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
4
+ from pydantic import (
5
+ BaseModel,
6
+ ConfigDict,
7
+ Field,
8
+ ValidationInfo,
9
+ field_validator,
10
+ model_validator,
11
+ )
5
12
 
6
13
  from evolib.config.base_component_config import CrossoverConfig, MutationConfig
7
14
  from evolib.interfaces.enums import RepresentationType
@@ -21,7 +28,7 @@ class VectorComponentConfig(BaseModel):
21
28
  type: vector
22
29
  structure: flat # "flat" | "net"
23
30
  dim: 16 # or a list for structured cases
24
- initializer: random_vector # name from the initializer registry
31
+ initializer: normal # name from the initializer registry
25
32
  bounds: [-1.0, 1.0]
26
33
  mutation:
27
34
  strategy: constant
@@ -86,7 +93,7 @@ class VectorComponentConfig(BaseModel):
86
93
  values: Optional[list[float]] = Field(
87
94
  default=None,
88
95
  description=(
89
- "Explicit values for 'fixed_vector' initializer. If 'dim' is absent it "
96
+ "Explicit values for 'fixed' initializer. If 'dim' is absent it "
90
97
  "will be inferred from the length of 'values'."
91
98
  ),
92
99
  )
@@ -102,7 +109,6 @@ class VectorComponentConfig(BaseModel):
102
109
 
103
110
  # Evolution (mutation / crossover)
104
111
  mutation: MutationConfig = Field(
105
- default=None,
106
112
  description=(
107
113
  "Mutation configuration. By default, 'probability' is an element-wise rate "
108
114
  "(per gene) in [0,1]; operators may optionally treat it as an apply gate."
@@ -143,18 +149,16 @@ class VectorComponentConfig(BaseModel):
143
149
  @classmethod
144
150
  def set_dim_for_fixed_vector(cls, config: dict[str, Any]) -> dict[str, Any]:
145
151
  """
146
- If using 'fixed_vector', ensure 'values' is provided and infer 'dim' if absent.
152
+ If using 'fixed', ensure 'values' is provided and infer 'dim' if absent.
147
153
 
148
154
  This keeps YAML concise and catches common mistakes early.
149
155
  """
150
156
  initializer = config.get("initializer")
151
157
  values = config.get("values")
152
158
 
153
- if initializer == "fixed_vector":
159
+ if initializer == "fixed":
154
160
  if not values:
155
- raise ValueError(
156
- "When using 'fixed_vector', 'values' must be provided."
157
- )
161
+ raise ValueError("When using 'fixed', 'values' must be provided.")
158
162
  if "dim" not in config:
159
163
  config["dim"] = len(values)
160
164
  return config
@@ -181,3 +185,30 @@ class VectorComponentConfig(BaseModel):
181
185
  else:
182
186
  raise TypeError("dim must be an int or list of ints")
183
187
  return dim
188
+
189
+ @field_validator("initializer")
190
+ @classmethod
191
+ def validate_initializer(cls, name: str, info: ValidationInfo) -> str:
192
+ """Validate allowed initializer names and provide clear errors for deprecated
193
+ names."""
194
+ if not isinstance(name, str) or not name.strip():
195
+ raise ValueError("initializer must be a non-empty string")
196
+
197
+ name = name.strip()
198
+
199
+ allowed = {"normal", "uniform", "zero", "fixed", "adaptive"}
200
+ if name not in allowed:
201
+ raise ValueError(
202
+ f"Unknown initializer '{name}'. " f"Allowed: {sorted(allowed)}"
203
+ )
204
+
205
+ # structure-aware check (only if structure is available in the data)
206
+ data = info.data or {}
207
+ structure = data.get("structure") or "flat"
208
+ if structure == "net" and name != "normal":
209
+ raise ValueError(
210
+ "For structure='net', initializer must be 'normal' "
211
+ "(use initializer: normal and structure: net)."
212
+ )
213
+
214
+ return name
@@ -14,7 +14,6 @@ from evonet.enums import ConnectionType, NeuronRole
14
14
 
15
15
  from evolib.config.evonet_component_config import DelayConfig, EvoNetComponentConfig
16
16
  from evolib.config.schema import FullConfig
17
- from evolib.interfaces.enum_helpers import resolve_recurrent_kinds
18
17
  from evolib.representation.evonet import EvoNet
19
18
 
20
19
 
@@ -158,14 +157,14 @@ def _build_architecture(
158
157
  dynamics_name = dynamics_cfg.name
159
158
  dynamics_params = dynamics_cfg.params or {}
160
159
 
161
- recurrent_kinds = resolve_recurrent_kinds(cfg.recurrent)
160
+ allowed_kinds = set(cfg.connectivity.recurrent)
162
161
  para.net.add_neuron(
163
162
  count=num_neurons,
164
163
  activation=activation_name,
165
164
  role=role,
166
165
  connection_init=connection_init,
167
166
  bias=0.0,
168
- recurrent=recurrent_kinds if role != NeuronRole.INPUT else None,
167
+ recurrent=allowed_kinds if role != NeuronRole.INPUT else None,
169
168
  connection_scope=para.connection_scope,
170
169
  connection_density=para.connection_density,
171
170
  dynamics_name=dynamics_name,