1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//! # Wiring Configurations for Neural Circuit Policies
//!
//! This module provides different connectivity patterns (wirings) that define how neurons
//! connect to each other in Neural Circuit Policy networks. Wiring determines the **sparsity**
//! and **structure** of the neural network.
//!
//! ## Key Concepts
//!
//! ### What is Wiring?
//!
//! Traditional RNNs use fully-connected layers where every neuron connects to every other neuron.
//! NCPs use **sparse, structured connectivity** inspired by biological neural circuits (specifically
//! the nervous system of *C. elegans*, a nematode with only 302 neurons).
//!
//! Wiring defines:
//! - **Which neurons connect** to which other neurons (adjacency matrix)
//! - **Synapse polarity** (+1 excitatory, -1 inhibitory)
//! - **Layer structure** (sensory → inter → command → motor in NCP)
//!
//! ### The `.build()` Method - IMPORTANT!
//!
//! **You must call `.build(input_dim)` before using any wiring with an RNN layer.**
//!
//! ```rust
//! use ncps::wirings::{AutoNCP, Wiring};
//!
//! // Create wiring configuration
//! let mut wiring = AutoNCP::new(32, 8, 0.5, 42);
//!
//! // REQUIRED: Build with input dimension before use
//! wiring.build(16); // 16 input features
//!
//! // Now the wiring is ready
//! assert!(wiring.is_built());
//! assert_eq!(wiring.input_dim(), Some(16));
//! ```
//!
//! **Why is `.build()` needed?**
//! - The sensory adjacency matrix (input → neurons) can only be created once we know the input size
//! - This allows the same wiring type to work with different input dimensions
//! - Calling `.build()` a second time with the same dimension is a no-op; with a different dimension it panics
//!
//! ## Choosing a Wiring Type
//!
//! | Wiring | Use Case | Sparsity | Structure |
//! |--------|----------|----------|-----------|
//! | [`AutoNCP`] | **Recommended default** - automatic parameter selection | Medium-High | 4-layer biological |
//! | [`NCP`] | Fine-grained control over layer sizes and connectivity | Configurable | 4-layer biological |
//! | [`FullyConnected`] | Baseline comparison, maximum expressiveness | None (dense) | Single layer |
//! | [`Random`] | Unstructured sparse networks for ablation studies | Configurable | Random |
//!
//! ## NCP Architecture (4-Layer Biological Structure)
//!
//! ```text
//! ┌─────────────────────────────────────────┐
//! │ Motor Neurons (output) │
//! │ - Final output layer │
//! │ - Size = output_dim │
//! └────────────────▲────────────────────────┘
//! │ motor_fanin connections
//! ┌────────────────┴────────────────────────┐
//! │ Command Neurons │
//! │ - Decision/integration layer │
//! │ - Has recurrent connections │
//! └────────────────▲────────────────────────┘
//! │ inter_fanout connections
//! ┌────────────────┴────────────────────────┐
//! │ Inter Neurons │
//! │ - Feature processing layer │
//! │ - Receives from sensory inputs │
//! └────────────────▲────────────────────────┘
//! │ sensory_fanout connections
//! ┌────────────────┴────────────────────────┐
//! │ Sensory Inputs (input) │
//! │ - External input features │
//! │ - Size = input_dim (set by .build()) │
//! └─────────────────────────────────────────┘
//! ```
//!
//! ## Quick Examples
//!
//! ### Using AutoNCP (Recommended)
//!
//! ```rust
//! use ncps::wirings::{AutoNCP, Wiring};
//!
//! // 32 total neurons, 8 motor outputs, 50% sparsity
//! let mut wiring = AutoNCP::new(32, 8, 0.5, 42);
//! wiring.build(16); // 16 input features
//!
//! println!("Total neurons: {}", wiring.units()); // 32
//! println!("Output size: {:?}", wiring.output_dim()); // Some(8)
//! println!("Internal synapses: {}", wiring.synapse_count());
//! println!("Sensory synapses: {}", wiring.sensory_synapse_count());
//! ```
//!
//! ### Using Manual NCP Configuration
//!
//! ```rust
//! use ncps::wirings::{NCP, Wiring};
//!
//! // Fine-grained control: 10 inter, 8 command, 4 motor neurons
//! let mut wiring = NCP::new(
//! 10, // inter_neurons
//! 8, // command_neurons
//! 4, // motor_neurons (output)
//! 4, // sensory_fanout: each sensory connects to 4 inter neurons
//! 4, // inter_fanout: each inter connects to 4 command neurons
//! 6, // recurrent_command_synapses
//! 4, // motor_fanin: each motor receives from 4 command neurons
//! 42, // seed for reproducibility
//! );
//! wiring.build(16);
//! ```
//!
//! ### Inspecting Connectivity
//!
//! ```rust
//! use ncps::wirings::{AutoNCP, Wiring};
//!
//! let mut wiring = AutoNCP::new(32, 8, 0.5, 42);
//! wiring.build(16);
//!
//! // Check neuron types
//! for i in 0..wiring.units() {
//! let neuron_type = wiring.get_type_of_neuron(i);
//! // Returns "motor", "command", or "inter"
//! }
//!
//! // Access adjacency matrices for visualization
//! let adj = wiring.adjacency_matrix(); // [units x units]
//! let sensory_adj = wiring.sensory_adjacency_matrix(); // [input_dim x units]
//! ```
use ;
pub use ;
pub use ;
pub use Random;
/// Configuration struct for serialization/deserialization of wiring structures