# SubspaceCoupling { #tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling }
```python
experimental.network_dynamics.coupling.SubspaceCoupling(
inner_coupling,
region_mapping,
regional_graph,
use_sparse=True,
**kwargs,
)
```
Coupling on regional subspace: aggregate nodes → couple regions → distribute.
Performs three-stage computation:
1. Aggregate node states to regional states (default: mean)
2. Apply inner coupling on regional graph
3. Distribute regional results to nodes (default: broadcast)
## Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|----------------|---------------------------------------------------------------------------------------------|-----------------------------------------------------------|------------|
| inner_coupling | [AbstractCoupling](`tvboptim.experimental.network_dynamics.coupling.base.AbstractCoupling`) | Coupling applied at regional level | _required_ |
| region_mapping | ([ndarray](`ndarray`), [shape](`shape`)([n_nodes](`n_nodes`))) | Maps each node to region ID (0 to n_regions-1) | _required_ |
| regional_graph | [AbstractGraph](`tvboptim.experimental.network_dynamics.graph.base.AbstractGraph`) | Regional connectivity (n_nodes must equal n_regions) | _required_ |
| use_sparse | [bool](`bool`) | Use sparse BCOO format for aggregation (memory efficient) | `True` |
| **kwargs | | Additional parameters for custom subclasses | `{}` |
## Attributes {.doc-section .doc-section-attributes}
| Name | Type | Description |
|-----------------|--------------|------------------------------------------------|
| n_regions | [int](`int`) | Number of regions from region_mapping |
| N_OUTPUT_STATES | [int](`int`) | Output coupling dimensions from inner_coupling |
## Notes {.doc-section .doc-section-notes}
Customization: Override ``aggregate()`` or ``distribute()`` for custom aggregation/
distribution strategies beyond mean/broadcast.
## Examples {.doc-section .doc-section-examples}
Surface-level network with regional delayed coupling:
```python
>>> region_mapping = jnp.array([...]) # [n_vertices] -> region IDs
>>> regional_graph = DenseDelayGraph.from_weights_delays(SC, delays)
>>>
>>> coupling = SubspaceCoupling(
... inner_coupling=DelayedLinearCoupling(incoming_states='S', G=0.5),
... region_mapping=region_mapping,
... regional_graph=regional_graph
... )
```
## Methods
| Name | Description |
| --- | --- |
| [aggregate](#tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.aggregate) | Aggregate node states to regional states (default: mean). |
| [compute](#tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.compute) | Compute coupling using cached aggregated state. |
| [describe](#tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.describe) | Generate description for network printer. |
| [distribute](#tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.distribute) | Distribute regional coupling to nodes (default: broadcast). |
| [prepare](#tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.prepare) | Prepare aggregation matrices, regional context, and inner coupling. |
| [update_state](#tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.update_state) | Update inner coupling state and cache aggregated state. |
### aggregate { #tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.aggregate }
```python
experimental.network_dynamics.coupling.SubspaceCoupling.aggregate(
node_state,
coupling_data,
)
```
Aggregate node states to regional states (default: mean).
Override for custom aggregation strategies (sum, weighted, etc).
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|---------------|----------------------------------------------------------------------------------------|----------------------------------------------------|------------|
| node_state | ([ndarray](`ndarray`), [shape](`shape`)([n_states](`n_states`), [n_nodes](`n_nodes`))) | Node-level states | _required_ |
| coupling_data | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Contains region_one_hot_normalized for aggregation | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|
| | ([ndarray](`ndarray`), [shape](`shape`)([n_states](`n_states`), [n_regions](`tvboptim.experimental.network_dynamics.coupling.subspace.SubspaceCoupling.n_regions`))) | Regional states |
#### Notes {.doc-section .doc-section-notes}
Default uses normalized one-hot matrix: node_state @ region_one_hot_normalized
Supports both dense and sparse (BCOO) matrices.
### compute { #tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.compute }
```python
experimental.network_dynamics.coupling.SubspaceCoupling.compute(
t,
state,
coupling_data,
coupling_state,
params,
graph,
)
```
Compute coupling using cached aggregated state.
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|----------------|----------------------------------------------------------------------------------------|-------------------------------------------------------------------------|------------|
| t | [float](`float`) | Current time | _required_ |
| state | ([ndarray](`ndarray`), [shape](`shape`)([n_states](`n_states`), [n_nodes](`n_nodes`))) | Not used - cached state from previous update_state() avoids aggregation | _required_ |
| coupling_data | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Static regional structures | _required_ |
| coupling_state | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Contains cached_regional_state, inner_state | _required_ |
| params | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Not used - inner coupling has own params | _required_ |
| graph | [AbstractGraph](`tvboptim.experimental.network_dynamics.graph.base.AbstractGraph`) | Not used - regional_graph used instead | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|----------------------------------------------------------------------------------------------------------|---------------------------|
| | ([ndarray](`ndarray`), [shape](`shape`)([n_coupling_inputs](`n_coupling_inputs`), [n_nodes](`n_nodes`))) | Node-level coupling input |
### describe { #tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.describe }
```python
experimental.network_dynamics.coupling.SubspaceCoupling.describe()
```
Generate description for network printer.
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|----------------|------------------------------------------------|
| | [dict](`dict`) | Coupling metadata with regional structure info |
### distribute { #tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.distribute }
```python
experimental.network_dynamics.coupling.SubspaceCoupling.distribute(
regional_coupling,
coupling_data,
)
```
Distribute regional coupling to nodes (default: broadcast).
Override for custom distribution strategies (scaled, weighted, etc).
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------|------------|
| regional_coupling | ([ndarray](`ndarray`), [shape](`shape`)([n_coupling_inputs](`n_coupling_inputs`), [n_regions](`tvboptim.experimental.network_dynamics.coupling.subspace.SubspaceCoupling.n_regions`))) | Regional coupling values | _required_ |
| coupling_data | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Contains region_mapping for distribution | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|----------------------------------------------------------------------------------------------------------|---------------------|
| | ([ndarray](`ndarray`), [shape](`shape`)([n_coupling_inputs](`n_coupling_inputs`), [n_nodes](`n_nodes`))) | Node-level coupling |
#### Notes {.doc-section .doc-section-notes}
Default broadcasts: each node receives its region's value via indexing.
### prepare { #tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.prepare }
```python
experimental.network_dynamics.coupling.SubspaceCoupling.prepare(
network,
dt,
t0,
t1,
)
```
Prepare aggregation matrices, regional context, and inner coupling.
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|---------|------------------------------------------------------------------|-----------------------------|------------|
| network | [Network](`tvboptim.experimental.network_dynamics.core.Network`) | Node-level network instance | _required_ |
| dt | [float](`float`) | Integration timestep | _required_ |
| t0 | [float](`float`) | Simulation time window | _required_ |
| t1 | [float](`float`) | Simulation time window | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|----------------|--------------------------------------------------------------------|--------------------------------------------------------|
| coupling_data | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Static data with region_one_hot_normalized, inner_data |
| coupling_state | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Mutable state with inner_state, cached_regional_state |
#### Raises {.doc-section .doc-section-raises}
| Name | Type | Description |
|--------|----------------------------|-------------------------------------------------|
| | [ValueError](`ValueError`) | If len(region_mapping) != network.graph.n_nodes |
### update_state { #tvboptim.experimental.network_dynamics.coupling.SubspaceCoupling.update_state }
```python
experimental.network_dynamics.coupling.SubspaceCoupling.update_state(
coupling_data,
coupling_state,
new_state,
)
```
Update inner coupling state and cache aggregated state.
#### Parameters {.doc-section .doc-section-parameters}
| Name | Type | Description | Default |
|----------------|----------------------------------------------------------------------------------------|-------------------------------------------------------|------------|
| coupling_data | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Static regional structures | _required_ |
| coupling_state | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Current state with inner_state, cached_regional_state | _required_ |
| new_state | ([ndarray](`ndarray`), [shape](`shape`)([n_states](`n_states`), [n_nodes](`n_nodes`))) | Network state after integration step | _required_ |
#### Returns {.doc-section .doc-section-returns}
| Name | Type | Description |
|--------|--------------------------------------------------------------------|------------------------------------------------------------------|
| | [Bunch](`tvboptim.experimental.network_dynamics.core.bunch.Bunch`) | Updated inner_state and cached_regional_state for next compute() |