Initial commit

Co-authored-by: Aradhana Dube <a.dube@rug.nl>
Co-authored-by: Renzo I. Barraza Altamirano <r.i.barraza.altamirano@rug.nl>
Co-authored-by: Paolo Gibertini <p.gibertini@rug.nl>
Co-authored-by: Luca D. Fehlings <l.d.fehlings@rug.nl>
This commit is contained in:
75 files changed
+447515

No files matched your search

@@ -0,0 +1,66 @@
# WereRabbit
The wererabbit neuron model is a two coupled oscillator that follows a predator- prey dynamic with a switching in the diagonal of the phaseplane. When the z in equation 1c represents the “moon phase”, when ever it cross that threshold, the rabbit (prey) becomes the predator.
## Circuit equation
$$
\begin{align}
C\frac{du}{dt} &= z I_{bias} - I_{n0} e^{\kappa v / U_t} [z + 26e^{-2} (0.5 - u) z] - I_a \\
C\frac{dv}{dt} &= -z I_{bias} + I_{n0} e^{\kappa u / U_t} [z + 26e^{-2} (0.5 - v) z] - I_a \\
z &= tanh(\rho (u-v))\\
I_a &= \sigma I_{bias} \\
\end{align}
$$
| **Parameter** | **Symbol** | **Definition** | **Value** |
|-----------|--------|------------|-------|
| Capacitance | C | Circuit capacitance | $0.1\,pF$ |
| Bias current | $I_{bias}$ | DC bias current for the fixpoint location | $100\,pA$
Leakage current | $I_{n0}$ | Transistor leakage current | $0.129\,pA$
Subthreshold slope | $\kappa$ | Transistor subthreshold slope factor | $0.39$
Thermal voltage | $U_t$ | Thermal voltage at room temperature | $25\,mV$
Bias scale | $\sigma$ | Scaling factor for the distance between fixpoints | $0.6$
Steepness | $\rho$ | Tanh steepness for the moonphase | $5$s
## Abstraction
To simplify the analysis of the model for simulation purposes, we can introduce a dimensionless time variable $\tau=tI_{bias}/C$, transforming the derivate of the equations in $\frac{d}{dt}=\frac{I_{bias}}{C}\frac{d}{d\tau}$. Substituting this time transformation on equation~\ref{eq:wererabbit:circ}
$$
\begin{equation}
C\frac{I_{bias}}{C}\frac{du}{d\tau} = z I_{bias} - I_{n0} e^{\kappa v / U_t} [z + 26e^{-2} (0.5 - u) z] - \sigma I_{bias}
\end{equation}
$$
And dividing by $I_{bias}$ on both sides:
$$
\begin{equation}
\frac{du}{d\tau} = z - \frac{I_{n0}}{I_{bias}} e^{\kappa v / U_t} [z + 26e^{-2} (0.5 - u) z] - \sigma
\end{equation}
$$
Obtaining the following set of equations:
$$
\begin{align}
z &= tanh(\kappa (u-v)) \\
\frac{du}{dt} &= z - z \alpha e^{\beta v} [1 + \gamma (0.5 - u)] - \sigma \\
\frac{dv}{dt} &= -z - z \alpha e^{\beta u} [1 + \gamma (0.5 - v)] - \sigma
\end{align}
$$
| **Parameter** | **Definition** | **Value** |
|---------------|----------------|-----------|
| $\tau$ | $tI_{bias}/C$ | -- |
| $\alpha$ | $I_{n0}/I_{bias}$ | $0.0129$ |
| $\beta$ | $\kappa/U_t$ | 15.6 |
| $\gamma$ | -- | $26e^{-2}$ |
| $\rho$ | Tanh steepness for the moonphase | 5 |
| $\sigma$ | Scaling factor for the distance between fixpoints | 0.6 |
## Examples
See the following interactive notebook for a practical example:
- [Basic Usage Example](wererabbit.ipynb) - Introduction to the WereRabbit model
@@ -0,0 +1,189 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 10,
"id": "cbf60fc3",
"metadata": {},
"outputs": [],
"source": [
"import diffrax as dfx\n",
"import jax\n",
"import jax.numpy as jnp\n",
"import jax.random as jrand\n",
"import matplotlib as mpl\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from felice.neuron_models import WereRabbit\n",
"\n",
"jax.config.update(\"jax_enable_x64\", True)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "5f28e42f",
"metadata": {},
"outputs": [],
"source": [
"key = jrand.key(0)\n",
"max_time = 40\n",
"\n",
"model = WereRabbit(dtype=jnp.float64)\n",
"\n",
"\n",
"def state_at_t(comp_times):\n",
" sol = dfx.diffeqsolve(\n",
" terms=dfx.ODETerm(model.dynamics),\n",
" solver=dfx.Tsit5(),\n",
" t0=0.0,\n",
" t1=max_time,\n",
" dt0=1e-3,\n",
" y0=model.init_state(1)\n",
" + jrand.uniform(key, shape=(1, 2), minval=0.1, maxval=0.5),\n",
" saveat=dfx.SaveAt(ts=comp_times),\n",
" max_steps=100000,\n",
" )\n",
"\n",
" return sol.ts, sol.ys"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "28924cfa",
"metadata": {},
"outputs": [],
"source": [
"comp_times = jnp.linspace(0.0, max_time, 2000)\n",
"_, state = state_at_t(comp_times)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "9d4d0829",
"metadata": {},
"outputs": [],
"source": [
"def compute_nullclines(snn, u_range, v_range, resolution=200):\n",
" \"\"\"\n",
" Compute nullclines\n",
" du/dt = 0 (u-nullcline)\n",
" dv/dt = 0 (v-nullcline)\n",
" \"\"\"\n",
" u_vals = jnp.linspace(u_range[0], u_range[1], resolution)\n",
" v_vals = jnp.linspace(v_range[0], v_range[1], resolution)\n",
" U, V = jnp.meshgrid(u_vals, v_vals)\n",
"\n",
" UV = jnp.stack(\n",
" [U.reshape(-1), V.reshape(-1), jnp.ones((resolution * resolution,))], axis=1\n",
" )\n",
" dS = snn.vector_field(UV)\n",
" dU = dS[:, 0].reshape(U.shape)\n",
" dV = dS[:, 1].reshape(V.shape)\n",
"\n",
" return U, V, dU, dV\n",
"\n",
"\n",
"def plot_vf(ax, snn, u_range, v_range):\n",
" import numpy as np\n",
"\n",
" u_sparse = jnp.linspace(u_range[0], u_range[1], 20)\n",
" v_sparse = jnp.linspace(v_range[0], v_range[1], 20)\n",
"\n",
" Us, Vs = jnp.meshgrid(u_sparse, v_sparse)\n",
"\n",
" U, V, dU, dV = compute_nullclines(snn, u_range, v_range, 200)\n",
"\n",
" UVs = jnp.stack([Us.reshape(-1), Vs.reshape(-1), jnp.ones((20 * 20,))], axis=1)\n",
" dS = snn.vector_field(UVs)\n",
" dUs = dS[:, 0].reshape(Us.shape)\n",
" dVs = dS[:, 1].reshape(Vs.shape)\n",
"\n",
" # Normalize for visualization\n",
" magnitude = np.sqrt(dUs**2 + dVs**2)\n",
" magnitude[magnitude == 0] = 1\n",
" dUs_norm = dUs / magnitude\n",
" dVs_norm = dVs / magnitude\n",
"\n",
" # Nullclines\n",
" ax.contour(U, V, dU, levels=[0], colors=\"blue\", linewidths=1, linestyles=\"-\")\n",
" ax.contour(U, V, dV, levels=[0], colors=\"red\", linewidths=1, linestyles=\"-\")\n",
"\n",
" # Vector field\n",
" ax.quiver(Us, Vs, dUs_norm, dVs_norm, magnitude, cmap=\"viridis\", alpha=0.6)\n",
"\n",
" ax.set_xlabel(\"u (Prey)\")\n",
" ax.set_ylabel(\"v (Predator)\")\n",
" ax.set_title(\"Wererabbit: Phase Portrait\")\n",
" ax.legend([\"u-nullcline (du/dt=0)\", \"v-nullcline (dv/dt=0)\"], loc=\"upper right\")\n",
" ax.set_xlim(u_range)\n",
" ax.set_ylim(v_range)\n",
" ax.axhline(y=0, color=\"gray\", linestyle=\"--\", alpha=0.3)\n",
" ax.axvline(x=0, color=\"gray\", linestyle=\"--\", alpha=0.3)"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "b1e166ef",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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WQghhBBCCCFE71BdXa2o1WoFUO6++26P5z777DMFUMaNG+da9sorryiAcsUVV3i0/fnnn10ZbB988IHHc1dccYUCKEOGDFEqKip8jmP+/PkeWa7u3DNgIyMjldzcXJ/baGhoUGJjYxVAueWWWxS73e6z3cMPP6wASkxMjNLQ0ODxnHuG3uTJk5Wmpiaf2+iI2tpaJT093edr0na/jEajsnfvXq82BQUFrn0aMmSI1/POrFxAiY+PVwoLC73a7N69WwkICFAA5eKLL/a7jbaZvYrimY3ZNovXF2fbk5nZW1VV5XpN1Gq1kpeX53rOPfMyKChI2bdvn9f6+fn5rgzoRx555LjH19zcrEyaNEkBlL/+9a9ezzsztB988MHj2u7s2bNd+/TTTz/5bFNVVeXKGr733nuPe+wdyexdu3atolKpFEAZMGCAa/kDDzzgWnfOnDle69lsNuXKK690tdm1a5fH8+7HEqDMmzev3bEea5xO3XnO+svsdXJmw0sWr+huktkrhBBCCCGEEALAVQsUvLN13ev1Ojkfr1692qPGrvu67tnC2dnZ/PDDDwC88sorrgzcti666CJXzc3PP//c73gfeughkpOTfT731VdfUVxcjNFo5M033/SZOQnw1FNPYTKZKCkpYdGiRX77evHFF9Hr9X6fP5agoCCuvvpqABYvXtxu23vuuYeMjAyv5QkJCTz++OOAY7KsDRs2+N3GE088QVxcnNfyIUOG8Ic//AGABQsWnNQJtxRFQVGUk1LL12w2s3jxYqZNm0ZxcTEAt912G0lJST7b33fffQwaNMhreWJiIr/61a8A2LRp03GPQ6vVcvPNNwO+31er1Qo43rvj8corrwBw0003ceGFF/psExoa6joevvjiC791rjujrKyMTz75hCuvvNK13b/85S8A2Gw2V53cSy65hCuuuMJrfbVazRtvvIFWqwXgvffe89vXhRdeyMUXX9xlY3fqznNWiN5Egr1CCCGEEEIIIVycwdm9e/d6TE60atUqwDPYO2LECIKDgykvL/e4xd8Z7E1MTCQ9Pd21fOnSpSiKQkBAAOPGjaOurs7vjzPo3F4A7pJLLvH7nLPMwcSJE9FoNH77sdvtriCgv74iIyMZP368376crFYrH3/8MZdffjkpKSkYjUaPSZleeOEFAA4cONDudpwBJl+uueYa1+M1a9ac0DbsdvtxTfjWkz7++GOP1zIoKIjzzz+fLVu2ADB16lTefPNNv+tfdNFFfp8bOHAgQLulEGbPns31119Penq6ayJA588999wD+H5fncfxCy+8wLx583xOZthWfX09a9euBWDatGntnifOydMqKirIyso65rb9aTvxWXR0NNOnT6ekpASAGTNmcMcLine truncated
"text/plain": [
"<Figure size 1380x520 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"with mpl.style.context(\"boilerplot.ieeetran\"):\n",
" fig, ax = plt.subplots(1, 2, figsize=(6.9, 2.6), dpi=200)\n",
" ax[0].plot(comp_times, state[:, 0, 0], label=\"x1\")\n",
" ax[0].plot(comp_times, state[:, 0, 1], label=\"x2\")\n",
" ax[0].legend([\"x1\", \"x2\"])\n",
"\n",
" plot_vf(ax[1], model, [-0.2, 0.5], [-0.2, 0.5])\n",
" ax[1].plot(state[:, 0, 0], state[:, 0, 1])\n",
" ax[1].plot(state[0, 0, 0], state[0, 0, 1], \".\", label=\"start\")\n",
" ax[1].plot(state[-1, 0, 0], state[-1, 0, 1], \".\", label=\"end\")\n",
" ax[1].legend()\n",
" plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f87852ec",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "felice",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}