Graphs
Event-based graph neural network layer for spike-graph message passing.
StochasticGraphLayer — GNN convolution where message passing happens via bitstreams. Takes adjacency matrix + per-node feature vectors, propagates through graph structure with SC arithmetic. Supports variable-topology graphs.
import numpy as np
from sc_neurocore.graphs import StochasticGraphLayer
adj = (np.random.rand(20, 20) > 0.7).astype(float)
np.fill_diagonal(adj, 0)
layer = StochasticGraphLayer(adj_matrix=adj, n_features=16)
features = np.random.rand(20, 16)
output = layer.forward(features)
sc_neurocore.graphs.gnn
StochasticGraphLayer
Event-Based Graph Convolution Layer.
Message Passing happens via Bitstreams.
Source code in src/sc_neurocore/graphs/gnn.py
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 | class StochasticGraphLayer:
"""
Event-Based Graph Convolution Layer.
Message Passing happens via Bitstreams.
"""
def __init__(self, adj_matrix: np.ndarray[Any, Any], n_features: int):
self.adj = adj_matrix # (N, N)
self.n_nodes = adj_matrix.shape[0]
self.n_features = n_features
# Weights: (Features, Features) - simple linear transform
self.weights = np.random.uniform(0, 1, (n_features, n_features))
def forward(self, node_features: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]:
"""
node_features: (N, Features)
"""
output = np.zeros_like(node_features)
# 1. Message Passing (Aggregation)
# For each node, sum neighbor features
# In SC, this is MUX aggregation
# Standard GCN: A * X * W
# Aggregation:
agg_features = np.dot(self.adj, node_features)
# Normalize by degree? (Simplified)
degrees = np.sum(self.adj, axis=1, keepdims=True)
degrees[degrees == 0] = 1
agg_features /= degrees
# 2. Transformation (Linear)
# Out = Agg * W
output = np.dot(agg_features, self.weights)
# 3. Non-linearity (Tanh/Sigmoid)
return np.tanh(output)
|
forward(node_features)
node_features: (N, Features)
Source code in src/sc_neurocore/graphs/gnn.py
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 | def forward(self, node_features: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]:
"""
node_features: (N, Features)
"""
output = np.zeros_like(node_features)
# 1. Message Passing (Aggregation)
# For each node, sum neighbor features
# In SC, this is MUX aggregation
# Standard GCN: A * X * W
# Aggregation:
agg_features = np.dot(self.adj, node_features)
# Normalize by degree? (Simplified)
degrees = np.sum(self.adj, axis=1, keepdims=True)
degrees[degrees == 0] = 1
agg_features /= degrees
# 2. Transformation (Linear)
# Out = Agg * W
output = np.dot(agg_features, self.weights)
# 3. Non-linearity (Tanh/Sigmoid)
return np.tanh(output)
|