Skip to content

Bio — Biological Computing Substrates

Biological computing interfaces: DNA-based weight storage, gene regulatory network modulation, and neuromodulatory dynamics (dopamine, serotonin, norepinephrine).

DNAEncoder — DNA Data Storage

Maps bitstreams to nucleotide sequences and back. Encoding: pairs of bits → nucleotides (00→A, 01→C, 10→G, 11→T). Decoding includes a configurable mutation rate that simulates sequencing errors.

Parameter Default Meaning
mutation_rate 0.001 Per-nucleotide mutation probability during decode

Odd-length bitstreams are zero-padded to even length.

GeneticRegulatoryLayer — Gene Expression Modulation

Neural activity drives protein production; protein levels modulate neuron thresholds. Implements a first-order ODE: dP/dt = α * spikes - β * P, clipped to [0, 10].

Parameter Default Meaning
n_neurons (required) Number of neurons
production_rate 0.01 Protein production rate (α)
decay_rate 0.005 Protein decay rate (β)

get_threshold_modulators() returns current protein levels — higher protein → higher effective threshold (inhibitory feedback).

NeuromodulatorSystem — Global Emotional System

Three neuromodulators with environmental feedback:

Chemical Baseline Effect
Dopamine (DA) 0.5 Lowers threshold (excitation)
Serotonin (5-HT) 0.5 Reduces noise (stabilization)
Norepinephrine (NE) 0.1 Increases noise + gain (exploration)

update_levels(reward, stress) adjusts chemicals. modulate_neuron(params) returns modified parameters.

Usage

Python
from sc_neurocore.bio import DNAEncoder, GeneticRegulatoryLayer, NeuromodulatorSystem
import numpy as np

# DNA storage roundtrip
enc = DNAEncoder(mutation_rate=0.0)
bits = np.array([1, 0, 0, 1, 1, 1, 0, 0], dtype=np.uint8)
dna = enc.encode(bits)   # "GCTA"
recovered = enc.decode(dna)
assert np.array_equal(bits, recovered)

# Gene regulation
grn = GeneticRegulatoryLayer(n_neurons=100)
for _ in range(50):
    spikes = (np.random.rand(100) < 0.3).astype(float)
    grn.step(spikes)
thresholds = grn.get_threshold_modulators()

# Neuromodulation
nm = NeuromodulatorSystem()
nm.update_levels(reward=0.8, stress=0.2)
params = nm.modulate_neuron({"v_threshold": 1.0, "noise_std": 0.1})

sc_neurocore.bio.dna_storage

DNAEncoder dataclass

Interface for DNA Data Storage. Maps Bitstreams to Nucleotides (A, C, T, G).

Source code in src/sc_neurocore/bio/dna_storage.py
Python
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
@dataclass
class DNAEncoder:
    """
    Interface for DNA Data Storage.
    Maps Bitstreams to Nucleotides (A, C, T, G).
    """

    mutation_rate: float = 0.001

    # Huffman-style mapping
    # 00 -> A, 01 -> C, 10 -> G, 11 -> T
    MAP = {(0, 0): "A", (0, 1): "C", (1, 0): "G", (1, 1): "T"}
    REV_MAP = {"A": (0, 0), "C": (0, 1), "G": (1, 0), "T": (1, 1)}

    def encode(self, bitstream: np.ndarray[Any, Any]) -> str:
        """
        Converts uint8 {0,1} bitstream to DNA string.
        """
        # Ensure even length
        if len(bitstream) % 2 != 0:
            bitstream = np.append(bitstream, 0)

        dna = []
        for i in range(0, len(bitstream), 2):
            pair = (bitstream[i], bitstream[i + 1])
            dna.append(self.MAP[pair])

        return "".join(dna)

    def decode(self, dna_str: str) -> np.ndarray[Any, Any]:
        """
        Converts DNA string back to bitstream.
        """
        bits: list[float] = []
        for char in dna_str:
            # Simulate mutation before decoding
            if np.random.random() < self.mutation_rate:
                char = np.random.choice(["A", "C", "T", "G"])

            pair = self.REV_MAP[char]
            bits.extend(pair)

        return np.array(bits, dtype=np.uint8)

encode(bitstream)

Converts uint8 {0,1} bitstream to DNA string.

Source code in src/sc_neurocore/bio/dna_storage.py
Python
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def encode(self, bitstream: np.ndarray[Any, Any]) -> str:
    """
    Converts uint8 {0,1} bitstream to DNA string.
    """
    # Ensure even length
    if len(bitstream) % 2 != 0:
        bitstream = np.append(bitstream, 0)

    dna = []
    for i in range(0, len(bitstream), 2):
        pair = (bitstream[i], bitstream[i + 1])
        dna.append(self.MAP[pair])

    return "".join(dna)

decode(dna_str)

Converts DNA string back to bitstream.

Source code in src/sc_neurocore/bio/dna_storage.py
Python
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def decode(self, dna_str: str) -> np.ndarray[Any, Any]:
    """
    Converts DNA string back to bitstream.
    """
    bits: list[float] = []
    for char in dna_str:
        # Simulate mutation before decoding
        if np.random.random() < self.mutation_rate:
            char = np.random.choice(["A", "C", "T", "G"])

        pair = self.REV_MAP[char]
        bits.extend(pair)

    return np.array(bits, dtype=np.uint8)

sc_neurocore.bio.grn

GeneticRegulatoryLayer dataclass

Bio-Hybrid Layer. Neural Activity -> Gene Expression (Protein) -> Neural Param Modulation.

Source code in src/sc_neurocore/bio/grn.py
Python
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
@dataclass
class GeneticRegulatoryLayer:
    """
    Bio-Hybrid Layer.
    Neural Activity -> Gene Expression (Protein) -> Neural Param Modulation.
    """

    n_neurons: int
    production_rate: float = 0.01
    decay_rate: float = 0.005

    def __post_init__(self) -> None:
        self.protein_levels = np.zeros(self.n_neurons)

    def step(self, spikes: np.ndarray[Any, Any]) -> None:
        """
        Update protein levels based on spike activity.
        """
        # dP/dt = alpha * spikes - beta * P
        delta = (self.production_rate * spikes) - (self.decay_rate * self.protein_levels)
        self.protein_levels += delta
        self.protein_levels = np.clip(self.protein_levels, 0, 10.0)  # type: ignore[assignment]

    def get_threshold_modulators(self) -> np.ndarray[Any, Any]:
        """
        Protein acts as inhibitor: Higher protein -> Higher threshold.
        """
        return self.protein_levels

step(spikes)

Update protein levels based on spike activity.

Source code in src/sc_neurocore/bio/grn.py
Python
28
29
30
31
32
33
34
35
def step(self, spikes: np.ndarray[Any, Any]) -> None:
    """
    Update protein levels based on spike activity.
    """
    # dP/dt = alpha * spikes - beta * P
    delta = (self.production_rate * spikes) - (self.decay_rate * self.protein_levels)
    self.protein_levels += delta
    self.protein_levels = np.clip(self.protein_levels, 0, 10.0)  # type: ignore[assignment]

get_threshold_modulators()

Protein acts as inhibitor: Higher protein -> Higher threshold.

Source code in src/sc_neurocore/bio/grn.py
Python
37
38
39
40
41
def get_threshold_modulators(self) -> np.ndarray[Any, Any]:
    """
    Protein acts as inhibitor: Higher protein -> Higher threshold.
    """
    return self.protein_levels

sc_neurocore.bio.neuromodulation

NeuromodulatorSystem dataclass

Global Emotional/Chemical System. Modulates neuron parameters based on Dopamine (DA), Serotonin (5HT), Norepinephrine (NE).

Source code in src/sc_neurocore/bio/neuromodulation.py
Python
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
@dataclass
class NeuromodulatorSystem:
    """
    Global Emotional/Chemical System.
    Modulates neuron parameters based on Dopamine (DA), Serotonin (5HT), Norepinephrine (NE).
    """

    da_level: float = 0.5  # Baseline
    ht_level: float = 0.5
    ne_level: float = 0.1

    def update_levels(self, reward: float, stress: float) -> None:
        """
        Adjust chemicals based on environmental feedback.
        """
        # Reward boosts Dopamine
        self.da_level += 0.1 * (reward - self.da_level)

        # Stress boosts Adrenaline (NE) and drops Serotonin (5HT)
        self.ne_level += 0.2 * (stress - self.ne_level)
        self.ht_level -= 0.1 * stress
        self.ht_level = np.clip(self.ht_level, 0.1, 1.0)

    def modulate_neuron(self, neuron_params: dict[str, Any]) -> dict[str, Any]:
        """
        Returns modified parameters for a StochasticLIFNeuron.
        """
        mod_params = neuron_params.copy()

        # Dopamine: Lowers Threshold (Excitation)
        if "v_threshold" in mod_params:
            mod_params["v_threshold"] *= 1.0 - 0.2 * self.da_level

        # 5-HT reduces noise (stabilisation effect)
        if "noise_std" in mod_params:
            mod_params["noise_std"] *= 1.0 - 0.5 * self.ht_level

        # Adrenaline: Increases Noise (Exploration) and Gain
        if "noise_std" in mod_params:
            mod_params["noise_std"] += 0.1 * self.ne_level

        return mod_params

update_levels(reward, stress)

Adjust chemicals based on environmental feedback.

Source code in src/sc_neurocore/bio/neuromodulation.py
Python
25
26
27
28
29
30
31
32
33
34
35
def update_levels(self, reward: float, stress: float) -> None:
    """
    Adjust chemicals based on environmental feedback.
    """
    # Reward boosts Dopamine
    self.da_level += 0.1 * (reward - self.da_level)

    # Stress boosts Adrenaline (NE) and drops Serotonin (5HT)
    self.ne_level += 0.2 * (stress - self.ne_level)
    self.ht_level -= 0.1 * stress
    self.ht_level = np.clip(self.ht_level, 0.1, 1.0)

modulate_neuron(neuron_params)

Returns modified parameters for a StochasticLIFNeuron.

Source code in src/sc_neurocore/bio/neuromodulation.py
Python
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
def modulate_neuron(self, neuron_params: dict[str, Any]) -> dict[str, Any]:
    """
    Returns modified parameters for a StochasticLIFNeuron.
    """
    mod_params = neuron_params.copy()

    # Dopamine: Lowers Threshold (Excitation)
    if "v_threshold" in mod_params:
        mod_params["v_threshold"] *= 1.0 - 0.2 * self.da_level

    # 5-HT reduces noise (stabilisation effect)
    if "noise_std" in mod_params:
        mod_params["noise_std"] *= 1.0 - 0.5 * self.ht_level

    # Adrenaline: Increases Noise (Exploration) and Gain
    if "noise_std" in mod_params:
        mod_params["noise_std"] += 0.1 * self.ne_level

    return mod_params