From 008be087a5b70c730ec753657036c38f2b134359 Mon Sep 17 00:00:00 2001 From: "C.A.P. Linssen" Date: Tue, 18 Feb 2025 18:57:09 +0100 Subject: [PATCH] fix discretisation bug; cleaned up notebook --- .../neuromodulated_stdp_synapse.nestml | 8 +- .../polebalancing.ipynb | 464 ++++-- .../synapse_test.ipynb | 1326 ++++++++++++++++- 3 files changed, 1635 insertions(+), 163 deletions(-) diff --git a/doc/tutorials/cart_pole_reinforcement_learning/neuromodulated_stdp_synapse.nestml b/doc/tutorials/cart_pole_reinforcement_learning/neuromodulated_stdp_synapse.nestml index 1421a2646..2a1d9686f 100644 --- a/doc/tutorials/cart_pole_reinforcement_learning/neuromodulated_stdp_synapse.nestml +++ b/doc/tutorials/cart_pole_reinforcement_learning/neuromodulated_stdp_synapse.nestml @@ -38,15 +38,15 @@ model neuromodulated_stdp_synapse: post_trace += 1 # potentiate synapse - w_ real = Wmax * ( w / Wmax + n * (lambda * ( 1. - ( w / Wmax ) )**mu_plus * pre_trace )) - w = min(Wmax, w_) + w += n * (lambda * ( 1. - w )**mu_plus * pre_trace ) + w = min(Wmax, w) onReceive(pre_spikes): pre_trace += 1 # depress synapse - w_ real = Wmax * ( w / Wmax - n * ( alpha * lambda * ( w / Wmax )**mu_minus * post_trace )) - w = max(Wmin, w_) + w -= n * ( alpha * lambda * w**mu_minus * post_trace ) + w = max(Wmin, w) # deliver spike to postsynaptic partner emit_spike(w, d) diff --git a/doc/tutorials/cart_pole_reinforcement_learning/polebalancing.ipynb b/doc/tutorials/cart_pole_reinforcement_learning/polebalancing.ipynb index 264cab7fa..d5d6d414c 100644 --- a/doc/tutorials/cart_pole_reinforcement_learning/polebalancing.ipynb +++ b/doc/tutorials/cart_pole_reinforcement_learning/polebalancing.ipynb @@ -5,7 +5,7 @@ "id": "f763ff4e", "metadata": {}, "source": [ - "# Polebalancing using NESTML" + "# Balancing a \"cart-pole\" inverse pendulum using NESTML" ] }, { @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "id": "6ded29bc", "metadata": {}, "outputs": [ @@ -47,94 +47,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "pygame 2.6.1 (SDL 2.28.4, Python 3.12.8)\n", + "pygame 2.5.0 (SDL 2.28.0, Python 3.11.4)\n", "Hello from the pygame community. https://www.pygame.org/contribute.html\n" ] } ], "source": [ - "import pygame as pg\n", - "from typing import Tuple\n", - "import numpy as np" - ] - }, - { - "cell_type": "markdown", - "id": "2283c79f", - "metadata": {}, - "source": [ - "Let's start with the renderer..." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "d1af3680-b849-48bb-a653-642b580a01aa", - "metadata": {}, - "outputs": [], - "source": [ - "#Renders the scene. IMPORTANT: Because ipycanvas uses the html canvas coordinates, the y-axis is inverted.\n", - "class Renderer():\n", - " def __init__(self, width: int, height: int, origin_x: int = 0, origin_y: int = 0, SCALE: int = 1) -> None:\n", - " self.width = width\n", - " self.height = height\n", - " self.origin = (origin_x, origin_y)\n", - " self.SCALE = SCALE #1m = SCALE pixels\n", - "\n", - " pg.display.init()\n", - " pg.display.set_caption(\"Pole Balancing Simulator\")\n", - " pg.font.init()\n", - " self.screen = pg.display.set_mode((width, height))\n", - " \n", - " #Translates global coordinates into screen coordinates\n", - " def translate(self, x: int, y: int) -> Tuple[int, int]:\n", - " return (x+self.origin[0], -y+self.origin[1])\n", - " \n", - " #Draws ground. offset is there to shift the ground below the car\n", - " def draw_ground(self, offset: int, color) -> None:\n", - " ground = pg.Rect(self.translate(-self.width//2, -offset * self.SCALE), (self.width, self.height-self.origin[1]-offset * self.SCALE))\n", - " pg.draw.rect(self.screen, color, ground)\n", + "%matplotlib inline\n", "\n", - " #Draws car. pos_y is omitted because the car's center should be at y = 0\n", - " def draw_car(self, pos_x: float, car_color = \"blue\", wheel_color = \"black\") -> None:\n", - " pos_x *= self.SCALE\n", - " #values, hard-coded for now, in meters\n", - " width = 0.5 * self.SCALE\n", - " height = 0.25 * self.SCALE\n", - " wheel_radius = 0.1 * self.SCALE\n", - "\n", - " car_body = pg.Rect(self.translate(pos_x - width/2, height/2), (width, height))\n", - " pg.draw.rect(self.screen, car_color, car_body)\n", - " pg.draw.circle(self.screen, wheel_color, \n", - " self.translate(pos_x - width/2 + wheel_radius, -height/2), wheel_radius)\n", - " pg.draw.circle(self.screen, wheel_color, \n", - " self.translate(pos_x + width/2 - wheel_radius, -height/2), wheel_radius)\n", - "\n", - " #Draws the pole\n", - " def draw_pole(self, pos_x: float, theta: float, length: float, width: float = 0.1, color = \"red\") -> None:\n", - " pos_x *= self.SCALE\n", - " width = int(width * self.SCALE)\n", - " pole_end_x = length * np.sin(theta) * self.SCALE + pos_x\n", - " pole_end_y = length * np.cos(theta) * self.SCALE\n", - " pg.draw.line(self.screen, color, self.translate(pos_x, 0), self.translate(pole_end_x, pole_end_y), width)\n", - "\n", - " #Clears the entire canvas\n", - " def draw_clear(self) -> None:\n", - " self.screen.fill(\"white\")\n", - "\n", - " #Draws physical values\n", - " def draw_stats(self, theta: float, dw: float, a: float, x: float, episode: int) -> None:\n", - " font = pg.font.Font(None, 24)\n", - " text = font.render(str(theta)[:4] + \" | \" + str(dw)[:4] + \" | \" + str(x)[:4] + \" | \" + str(a)[:4] + \" | episode: \" + str(episode), True, (10,10,10))\n", - " textpos = text.get_rect(centerx=self.screen.get_width() / 2, y=10)\n", - " self.screen.blit(text, textpos)\n", + "from typing import Tuple\n", "\n", - " #Get the \n", - " def get_relative_mouse_x(self, mouse_x:float) -> float:\n", - " return (mouse_x-self.origin[0])/self.SCALE\n", - " \n", - " def display(self) -> None:\n", - " pg.display.flip()" + "import sys\n", + "import pygame as pg\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from IPython import display" ] }, { @@ -142,7 +69,7 @@ "id": "d6362d90", "metadata": {}, "source": [ - "## Physics Updates" + "## Physics of the inverse pendulum" ] }, { @@ -250,17 +177,25 @@ "$$" ] }, + { + "cell_type": "markdown", + "id": "89f5aa4a", + "metadata": {}, + "source": [ + "To render the environment for visual inspection, we make a class ``Renderer`` that uses pygame:" + ] + }, { "cell_type": "markdown", "id": "376c6dd1", "metadata": {}, "source": [ - "# TODO: FINISH EQUATION DERIVATION (SOLVE EQUATION REFERENCING?)" + "Physics is implemented in a class ``Physics``:" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "6b5f4227", "metadata": {}, "outputs": [], @@ -293,7 +228,7 @@ " def update(self, force, mouse_x) -> Tuple[float, float]:\n", " nudge_force = 0\n", " if mouse_x is not None:\n", - " nudge_force = -1 if mouse_x > self.x else 1\n", + " nudge_force = -10 if mouse_x > self.x else 10\n", " return (self.dw_step(force, nudge_force), self.a_step(force))\n", " \n", " #get state of the system that agent can see\n", @@ -309,51 +244,203 @@ " self.dw = 0\n" ] }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d1af3680-b849-48bb-a653-642b580a01aa", + "metadata": {}, + "outputs": [], + "source": [ + "#Renders the scene. IMPORTANT: Because ipycanvas uses the html canvas coordinates, the y-axis is inverted.\n", + "class Renderer():\n", + " def __init__(self, width: int, height: int, origin_x: int = 0, origin_y: int = 0, SCALE: int = 1) -> None:\n", + " self.width = width\n", + " self.height = height\n", + " self.origin = (origin_x, origin_y)\n", + " self.SCALE = SCALE #1m = SCALE pixels\n", + "\n", + " pg.display.init()\n", + " pg.display.set_caption(\"Pole Balancing Simulator\")\n", + " pg.font.init()\n", + " self.screen = pg.display.set_mode((width, height))\n", + " \n", + " #Translates global coordinates into screen coordinates\n", + " def translate(self, x: int, y: int) -> Tuple[int, int]:\n", + " return (x+self.origin[0], -y+self.origin[1])\n", + " \n", + " #Draws ground. offset is there to shift the ground below the car\n", + " def draw_ground(self, offset: int, color) -> None:\n", + " ground = pg.Rect(self.translate(-self.width//2, -offset * self.SCALE), (self.width, self.height-self.origin[1]-offset * self.SCALE))\n", + " pg.draw.rect(self.screen, color, ground)\n", + "\n", + " #Draws car. pos_y is omitted because the car's center should be at y = 0\n", + " def draw_car(self, pos_x: float, car_color = \"blue\", wheel_color = \"black\") -> None:\n", + " pos_x *= self.SCALE\n", + " #values, hard-coded for now, in meters\n", + " width = 0.5 * self.SCALE\n", + " height = 0.25 * self.SCALE\n", + " wheel_radius = 0.1 * self.SCALE\n", + "\n", + " car_body = pg.Rect(self.translate(pos_x - width/2, height/2), (width, height))\n", + " pg.draw.rect(self.screen, car_color, car_body)\n", + " pg.draw.circle(self.screen, wheel_color, \n", + " self.translate(pos_x - width/2 + wheel_radius, -height/2), wheel_radius)\n", + " pg.draw.circle(self.screen, wheel_color, \n", + " self.translate(pos_x + width/2 - wheel_radius, -height/2), wheel_radius)\n", + "\n", + " #Draws the pole\n", + " def draw_pole(self, pos_x: float, theta: float, length: float, width: float = 0.1, color = \"red\") -> None:\n", + " pos_x *= self.SCALE\n", + " width = int(width * self.SCALE)\n", + " pole_end_x = length * np.sin(theta) * self.SCALE + pos_x\n", + " pole_end_y = length * np.cos(theta) * self.SCALE\n", + " pg.draw.line(self.screen, color, self.translate(pos_x, 0), self.translate(pole_end_x, pole_end_y), width)\n", + "\n", + " #Clears the entire canvas\n", + " def draw_clear(self) -> None:\n", + " self.screen.fill(\"white\")\n", + "\n", + " #Draws physical values\n", + " def draw_stats(self, theta: float, dw: float, a: float, x: float, episode: int) -> None:\n", + " font = pg.font.Font(None, 24)\n", + " text = font.render(str(theta)[:4] + \" | \" + str(dw)[:4] + \" | \" + str(x)[:4] + \" | \" + str(a)[:4] + \" | episode: \" + str(episode), True, (10,10,10))\n", + " textpos = text.get_rect(centerx=self.screen.get_width() / 2, y=10)\n", + " self.screen.blit(text, textpos)\n", + "\n", + " #Get the \n", + " def get_relative_mouse_x(self, mouse_x:float) -> float:\n", + " return (mouse_x-self.origin[0])/self.SCALE\n", + " \n", + " def display(self) -> None:\n", + " pg.display.flip()" + ] + }, { "cell_type": "markdown", - "id": "76793d12", + "id": "01e12bb2", "metadata": {}, "source": [ - "# The Agent (BOXES)" + "Let's see the physics in action (without an agent controlling the cart yet):" ] }, { "cell_type": "code", "execution_count": 4, - "id": "5707ac4a", + "id": "abf4c084", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "SystemExit", + "evalue": "", + "output_type": "error", + "traceback": [ + "An exception has occurred, use %tb to see the full traceback.\n", + "\u001b[0;31mSystemExit\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/usr/lib/python3/dist-packages/IPython/core/interactiveshell.py:3386: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.\n", + " warn(\"To exit: use 'exit', 'quit', or Ctrl-D.\", stacklevel=1)\n" + ] + } + ], "source": [ + "r = Renderer(1200, 800, 600, 500, 400)\n", + "clock = pg.time.Clock()\n", + "running = True\n", "\n", - "class Agent:\n", - " def __init__(self, initial_state: Tuple[float,float,float,float]) -> None:\n", + "p = Physics(0, (np.random.rand() - 1) / 10)\n", + "\n", + "steps_per_episode = 0\n", + "max_steps = 0\n", + "\n", + "toggle_sim = False\n", + "\n", + "while running:\n", + " steps_per_episode += 1\n", + "\n", + " force = 0\n", + " mouse_x = None\n", "\n", - " #thresholds for discretizing the state space\n", + " # poll for events\n", + " for event in pg.event.get():\n", + " if event.type == pg.QUIT:\n", + " running = False\n", + " pg.quit()\n", + " sys.exit()\n", + " quit()\n", + " elif event.type == pg.MOUSEBUTTONDOWN:\n", + " mouse_x = r.get_relative_mouse_x(pg.mouse.get_pos()[0])\n", + "\n", + " force = 0 # no controller, no action\n", + " theta, x = p.update(force, mouse_x)\n", + " \n", + " r.draw_clear()\n", + " r.draw_ground(0.2, \"grey\")\n", + " r.draw_car(x)\n", + " r.draw_pole(x, theta, 2*p.l, 0.02)\n", + " r.draw_stats(theta*180/np.pi, p.w*180/np.pi, x, 0, 0)\n", + " r.display()\n", + "\n", + " clock.tick(50) # limits FPS to 50\n" + ] + }, + { + "cell_type": "markdown", + "id": "76793d12", + "metadata": {}, + "source": [ + "# The Agent\n", + "\n", + "In the base class ``Agent``...\n", + "\n", + "\"boxes\" (discretizing the state space)..." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "1309d0fe", + "metadata": {}, + "outputs": [], + "source": [ + "class Agent:\n", + " def __init__(self, initial_state: Tuple[float, float, float, float]) -> None:\n", " self.x_thresholds = np.array([-2.4, -0.8, 0.8, 2.4])\n", " self.theta_thresholds = np.array([-12, -6, -1, 0, 1, 6, 12])\n", - " self.theta_thresholds = self.theta_thresholds /180 * np.pi\n", + " self.theta_thresholds = self.theta_thresholds / 180 * np.pi\n", " self.v_thresholds = np.array([float(\"-inf\"), -0.5, 0.5, float(\"+inf\")]) #open intervals ignored here\n", " self.w_thresholds = np.array([float(\"-inf\"), -50, 50, float(\"+inf\")]) #open intervals ignored here\n", " self.w_thresholds = self.w_thresholds /180 * np.pi\n", "\n", - " self.dimensions = (len(self.x_thresholds) - 1, len(self.theta_thresholds) - 1, len(self.v_thresholds) - 1, len(self.w_thresholds) - 1)\n", + " self.dimensions = (len(self.x_thresholds),\n", + " len(self.theta_thresholds),\n", + " len(self.v_thresholds),\n", + " len(self.w_thresholds))\n", "\n", " self.boxes = np.random.rand(self.dimensions[0], \n", " self.dimensions[1], \n", " self.dimensions[2], \n", " self.dimensions[3], \n", - " 2) #one q-value for left and right respectively\n", + " 2) # one q-value for left and right respectively\n", " box = self.get_box(initial_state)\n", " self.current_box = self.boxes[box[0], box[1], box[2], box[3], :]\n", "\n", " self.episode = 1\n", - " \n", + "\n", " def discretize(self, value, thresholds):\n", - " for i, limit in enumerate(thresholds):\n", - " if value < limit:\n", - " return i - 1\n", - " return -1\n", + " thresholds = np.asarray(thresholds)\n", + " box_idx = np.digitize(value, thresholds)\n", + "\n", + " if box_idx == 0 or box_idx > len(thresholds) - 1:\n", + " # below the lowest or above the highest threshold\n", + " return -1\n", "\n", + " return box_idx - 1\n", + " \n", " def get_box(self, state: Tuple[float,float,float,float]) -> Tuple[int,int,int,int]:\n", " return (self.discretize(state[0], self.x_thresholds),\n", " self.discretize(state[1], self.theta_thresholds),\n", @@ -363,32 +450,97 @@ " def get_episode(self) -> int:\n", " return self.episode\n", " \n", - " \n", " def failure_reset(self, state: Tuple[float,float,float,float]):\n", " box = self.get_box(state)\n", " self.current_box = self.boxes[box[0], box[1], box[2], box[3], :]\n", - " self.episode += 1\n", + " self.episode += 1" + ] + }, + { + "cell_type": "markdown", + "id": "891151de", + "metadata": {}, + "source": [ + "Show discretisation:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5478adde", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "agent = Agent((0,0,0,0))\n", + "\n", + "fig, ax = plt.subplots()\n", + "theta_min = np.amin(agent.theta_thresholds)\n", + "theta_max = np.amax(agent.theta_thresholds)\n", + "theta_range = np.linspace(theta_min - .1 * np.abs(theta_min), theta_max + .1 * np.abs(theta_max), 1000)\n", "\n", + "theta_idx = np.nan * np.ones_like(theta_range)\n", + "for i in range(len(theta_range)):\n", + " theta_idx[i] = agent.discretize(theta_range[i], agent.theta_thresholds)\n", "\n", + "ax.plot(theta_range, theta_idx)\n", + "ax.set_xlabel(r\"$\\theta$\")\n", + "ax.set_ylabel(r\"$\\theta$ bin index\")\n", + "ax.grid(True)" + ] + }, + { + "cell_type": "markdown", + "id": "9942b606", + "metadata": {}, + "source": [ + "## Non-spiking version\n", + "\n", + "..." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "5707ac4a", + "metadata": {}, + "outputs": [], + "source": [ "class NonSpikingAgent(Agent):\n", " def __init__(self, initial_state: Tuple[float,float,float,float], learning_rate, learning_decay, epsilon, epsilon_decay, discount_factor) -> None:\n", " super().__init__(initial_state)\n", "\n", " #learning paramters\n", " self.learning_rate = learning_rate\n", - " self. learning_decay = learning_decay\n", + " self.learning_decay = learning_decay\n", " self.epsilon = epsilon\n", " self.epsilon_decay = epsilon_decay\n", " self.discount_factor = discount_factor\n", "\n", - " #returns 0 if the action is \"left\", else \"1\"\n", " def choose_action(self) -> int:\n", - " self.action = np.random.choice([np.argmax(self.current_box), np.argmin(self.current_box)], p=[1-self.epsilon, self.epsilon])\n", + " r\"\"\"\n", + " Returns 0 if the action is \"left\", else \"1\"\n", + " \"\"\"\n", + " self.action = np.random.choice([np.argmax(self.current_box), np.argmin(self.current_box)],\n", + " p=[1 - self.epsilon, self.epsilon])\n", " return self.action\n", " \n", - " #returns 0 if no failure occured, else 1\n", - " #reward is -1 on failure and 0 else\n", " def update(self, next_state: Tuple[float,float,float,float]) -> int:\n", + " r\"\"\"\n", + " Returns 0 if no failure occured, else 1.\n", + " \n", + " Reward is -1 on failure and 0 otherwise.\n", + " \"\"\"\n", " box = self.get_box(next_state)\n", " if -1 in box:\n", " self.current_box[self.action] += self.learning_rate * -1\n", @@ -411,23 +563,24 @@ "id": "ba2e6cd3", "metadata": {}, "source": [ - "# Plot Renderer" + "Plot renderer:" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 11, "id": "3f9b07a1", "metadata": {}, "outputs": [], "source": [ - "import matplotlib.pyplot as plt\n", - "%matplotlib qt\n", + "#%matplotlib qt\n", "class Non_Spiking_PlotRenderer():\n", " def __init__(self, init_x = [0], init_y = [0]) -> None:\n", - " plt.ion()\n", + " #plt.ion()\n", " #Construct lifetime plot\n", - " self.lifetime_fig, self.lifetime_ax = plt.subplots()\n", + " self.lifetime_fig, ax = plt.subplots(nrows=2)\n", + " self.lifetime_ax = ax[0]\n", + " self.epsilon_ax = ax[1]\n", " self.x = init_x\n", " self.y = init_y\n", " self.max_lifetime = 0\n", @@ -442,7 +595,6 @@ " self.cmap = plt.cm.coolwarm\n", " \n", " def update(self, x, y, boxes) -> None:\n", - " print(x)\n", " self.x.append(x)\n", " self.y.append(y)\n", " self.max_lifetime = max(self.max_lifetime, y)\n", @@ -454,9 +606,13 @@ " q_values = boxes[:,:,:,:,0] - boxes[:,:,:,:,1]\n", " self.q_value_ax.imshow(np.mean(q_values, axis = (1,3)), cmap=plt.cm.coolwarm, interpolation='none')\n", "\n", - " plt.draw\n", - " plt.pause(0.0001)\n", - "\n" + " self.lifetime_fig.canvas.draw()\n", + " self.lifetime_fig.canvas.flush_events()\n", + " \n", + " display.clear_output(wait=True)\n", + " display.display(self.lifetime_fig)\n", + "\n", + " #plt.pause(0.0001)\n" ] }, { @@ -464,31 +620,45 @@ "id": "2cd7786b", "metadata": {}, "source": [ - "# Executing Non-Spiking-Agent" + "Executing Non-Spiking-Agent:" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "717eda26-e385-494f-bdca-9847eefe01ca", "metadata": {}, "outputs": [ { "data": { + "image/png": "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AKjzfutfa43GjBmDiRMnIjg4GElJSXj99dcxduxYxMbGQiKRWDu8RtFoNHj55ZcxaNAg9OjRA4D2PkulUri5udXatzXc57quFwAef/xxBAYGwt/fH6dPn8Z//vMfXLp0CVu3brVitI1z5swZREZGoqKiAk5OTti2bRu6deuGhISEVnl/b3e9QOu8v5s3b8bJkydx/PjxW15rDv+H22xi1BaNHTvW8HWvXr0QERGBwMBA/PDDD5g5c6YVIyNLefTRRw1f9+zZE7169UJoaCj27duHkSNHWjGyxpszZw7Onj3bqurk6nO76501a5bh6549e8LPzw8jR45EUlISQkNDmzpMswgLC0NCQgKKiorw008/Yfr06di/f7+1w7KY211vt27dWt39TU9Px0svvYRdu3bBzs7O2uHUqc12pXl5eUEikdxS6a5QKODr62ulqJqWm5sbOnfujCtXrlg7FIvT39O2fL8BICQkBF5eXi3+nj///PP4448/sHfvXrRv396w3dfXF5WVlSgsLKy1f0u/z7e73rpEREQAQIu+x1KpFB07dkR4eDiWL1+O3r1747///W+rvb+3u966tPT7GxcXh5ycHNx1112wsbGBjY0N9u/fj1WrVsHGxgZyudzq97jNJkZSqRTh4eGIiYkxbNNoNIiJianVt9ualZSUICkpCX5+ftYOxeKCg4Ph6+tb634rlUocPXq0zdxvAMjIyEB+fn6LveeCIOD555/Htm3bsGfPHgQHB9d6PTw8HLa2trXu86VLl5CWltYi7/OdrrcuCQkJANBi73FdNBoNVCpVq7u/t6O/3rq09Ps7cuRInDlzBgkJCYZHv379MGXKFMPXVr/HTVLi3Uxt3rxZkMlkwoYNG4Tz588Ls2bNEtzc3ITs7Gxrh2YR//73v4V9+/YJKSkpwj///CNERUUJXl5eQk5OjrVDM4vi4mIhPj5eiI+PFwAIH330kRAfHy+kpqYKgiAIK1asENzc3IRff/1VOH36tPDggw8KwcHBQnl5uZUjb7j6rrm4uFh45ZVXhNjYWCElJUXYvXu3cNdddwmdOnUSKioqrB16gzz77LOCq6ursG/fPiErK8vwKCsrM+wze/ZsoUOHDsKePXuEEydOCJGRkUJkZKQVo264O13vlStXhLfeeks4ceKEkJKSIvz6669CSEiIMHToUCtH3nDz5s0T9u/fL6SkpAinT58W5s2bJ4hEIuHvv/8WBKF13V9BqP96W+P9rcvNI++sfY/bdGIkCILwySefCB06dBCkUqkwYMAA4ciRI9YOyWImT54s+Pn5CVKpVGjXrp0wefJk4cqVK9YOy2z27t0rALjlMX36dEEQtEP233jjDUEulwsymUwYOXKkcOnSJesG3Uj1XXNZWZkwatQowdvbW7C1tRUCAwOFp59+ukUn/nVdKwDh66+/NuxTXl4uPPfcc4K7u7vg4OAgPPTQQ0JWVpb1gm6EO11vWlqaMHToUMHDw0OQyWRCx44dhVdffVUoKiqybuCN8OSTTwqBgYGCVCoVvL29hZEjRxqSIkFoXfdXEOq/3tZ4f+tyc2Jk7XssEgRBaJq2KSIiIqLmrc3WGBERERHdjIkRERERkQ4TIyIiIiIdJkZEREREOkyMiIiIiHSYGBERERHpMDEiIiIi0mlWidGBAwcwfvx4+Pv7QyQS4ZdffrnjMfv27cNdd90FmUyGjh07YsOGDRaPk4iIiFqnZpUYlZaWonfv3lizZo1R+6ekpGDcuHEYPnw4EhIS8PLLL+Opp57CX3/9ZeFIiag5uHr1KkQikWH9KEt44oknMGHCBIudn4iaFxtrB1DT2LFjMXbsWKP3X79+PYKDg/Hhhx8CALp27YpDhw7h448/xujRoy0VJhGZyRNPPIFvvvnmlu2jR4/Gzp0773h8QEAAsrKy4OXlZYnwiKgNalaJkaliY2MRFRVVa9vo0aPx8ssv13ucSqWqtXKxRqNBQUEBPD09IRKJLBEqEdWhsrISUVFRWLt2ba3tUqkUSqXSqHM4ODigrKzMEuEB0MZYVVVldDxE1HQEQUBxcTH8/f0hFpunE6xFJ0bZ2dmQy+W1tsnlciiVSpSXl8Pe3r7O45YvX44lS5Y0RYhEZITOnTtbO4Q7cnV1tXYIRHQb6enpaN++vVnO1aITo4aaP38+oqOjDc+LiorQoUMHpKenw8XFxYqRERERkbGUSiUCAgLg7OxstnO26MTI19cXCoWi1jaFQgEXF5fbthYBgEwmg0wmu2W7i4sLEyMiIqIWxpxlMM1qVJqpIiMjERMTU2vbrl27EBkZaaWIiIiIqCVrVolRSUkJEhISDENvU1JSkJCQgLS0NADaLrBp06YZ9p89ezaSk5Px2muv4eLFi1i7di1++OEHzJ071xrhExERUQvXrBKjEydOoG/fvujbty8AIDo6Gn379sWiRYsAAFlZWYYkCQCCg4Oxfft27Nq1C71798aHH36IL774gkP1iYiIqEFEgiAI1g7C2pRKJVxdXVFUVMQaIyIiohbCEp/fzarFiIiIiMiamBgRERER6TAxIiIiItJhYkRERESkw8SIiIiISIeJEREREZEOEyMiIiIiHSZGRERERDpMjIiIiIh0mBgRERER6TAxIiIiItJhYkRERESkw8SIiIiISIeJEREREZEOEyMiIiIiHSZGRERERDpMjIiIiIh0mBgRERER6TAxIiIiItJhYkRERESkw8SIiIiISIeJEREREZEOEyMiIiIinWaZGK1ZswZBQUGws7NDREQEjh07Vu/+K1euRFhYGOzt7REQEIC5c+eioqKiiaIlIiKi1qLZJUZbtmxBdHQ0Fi9ejJMnT6J3794YPXo0cnJy6tx/06ZNmDdvHhYvXowLFy7gyy+/xJYtW/D66683ceRERETU0jW7xOijjz7C008/jRkzZqBbt25Yv349HBwc8NVXX9W5/+HDhzFo0CA8/vjjCAoKwqhRo/DYY4/dsZWJiIiI6GbNKjGqrKxEXFwcoqKiDNvEYjGioqIQGxtb5zEDBw5EXFycIRFKTk7Gjh07cN999932fVQqFZRKZa0HERERkY21A6gpLy8ParUacrm81na5XI6LFy/Weczjjz+OvLw8DB48GIIgoLq6GrNnz663K2358uVYsmSJWWMnIiKilq9ZtRg1xL59+7Bs2TKsXbsWJ0+exNatW7F9+3YsXbr0tsfMnz8fRUVFhkd6enoTRkxERETNVbNqMfLy8oJEIoFCoai1XaFQwNfXt85j3njjDUydOhVPPfUUAKBnz54oLS3FrFmzsGDBAojFt+Z+MpkMMpnM/BdARERELVqzajGSSqUIDw9HTEyMYZtGo0FMTAwiIyPrPKasrOyW5EcikQAABEGwXLBERETU6jSrFiMAiI6OxvTp09GvXz8MGDAAK1euRGlpKWbMmAEAmDZtGtq1a4fly5cDAMaPH4+PPvoIffv2RUREBK5cuYI33ngD48ePNyRIRERERMZodonR5MmTkZubi0WLFiE7Oxt9+vTBzp07DQXZaWlptVqIFi5cCJFIhIULFyIzMxPe3t4YP3483nnnHWtdAhEREbVQIoH9TVAqlXB1dUVRURFc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\n", "text/plain": [ - "'\\n\\nimport sys\\n\\nr = Renderer(1200, 800, 600, 500, 400)\\nclock = pg.time.Clock()\\nrunning = True\\n\\np = Physics(0, (np.random.rand() - 1) / 10)\\n\\na = NonSpikingAgent(p.get_state(), 0.5, 0.9999999999999, 1, 0.995, 0.99)\\n\\nplot = Non_Spiking_PlotRenderer()\\n\\nsteps_per_episode = 0\\nmax_steps = 0\\n\\nwindow_size = 30\\nwindow = np.zeros(30)\\navg_lifetime = 20000\\n\\ntoggle_sim = False\\n\\nwhile running:\\n steps_per_episode += 1\\n\\n force = 0\\n mouse_x = None\\n\\n # poll for events\\n for event in pg.event.get():\\n if event.type == pg.QUIT:\\n running = False\\n pg.quit()\\n sys.exit()\\n quit()\\n elif event.type == pg.MOUSEBUTTONDOWN:\\n mouse_x = r.get_relative_mouse_x(pg.mouse.get_pos()[0])\\n elif event.type == pg.KEYDOWN:\\n toggle_sim ^= pg.key.get_pressed()[pg.K_SPACE]\\n\\n # agent chooses action, simulation is updated and reward is calculated\\n force = 10 if a.choose_action() else -10\\n theta, x = p.update(force, mouse_x)\\n failure = a.update(p.get_state())\\n\\n if failure:\\n p.reset()\\n a.failure_reset(p.get_state())\\n plot.update(a.get_episode(), steps_per_episode, a.boxes)\\n window = np.roll(window, 1)\\n window[0] = steps_per_episode\\n steps_per_episode = 0\\n \\n \\n if np.mean(window) >= avg_lifetime or toggle_sim:\\n r.draw_clear()\\n r.draw_ground(0.2, \"grey\")\\n r.draw_car(x)\\n r.draw_pole(x, theta, 2*p.l, 0.02)\\n r.draw_stats(theta*180/np.pi, p.w*180/np.pi, x, p.a, a.get_episode())\\n r.display()\\n\\n clock.tick(50) # limits FPS to 50\\n'" + "
" ] }, - "execution_count": 6, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n", + "9\n", + "10\n" + ] } ], "source": [ - "\"\"\"\n", - "\n", - "import sys\n", - "\n", + "%pdb\n", "r = Renderer(1200, 800, 600, 500, 400)\n", "clock = pg.time.Clock()\n", "running = True\n", @@ -506,7 +676,7 @@ "window = np.zeros(30)\n", "avg_lifetime = 20000\n", "\n", - "toggle_sim = False\n", + "toggle_sim = True\n", "\n", "while running:\n", " steps_per_episode += 1\n", @@ -548,8 +718,7 @@ " r.draw_stats(theta*180/np.pi, p.w*180/np.pi, x, p.a, a.get_episode())\n", " r.display()\n", "\n", - " clock.tick(50) # limits FPS to 50\n", - "\"\"\"" + " clock.tick(50) # limits FPS to 50" ] }, { @@ -566,7 +735,9 @@ "id": "83e05060", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "pass" + ] }, { "cell_type": "markdown", @@ -608,7 +779,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 1, "id": "e9bdcc5a", "metadata": {}, "outputs": [], @@ -649,6 +820,7 @@ " \n", " self.fig.canvas.draw()\n", " self.fig.canvas.flush_events()\n", + " \n", " plt.pause(0.0001)" ] }, @@ -3021,11 +3193,33 @@ "\n", " clock.tick(50) # limits FPS to 50" ] + }, + { + "cell_type": "markdown", + "id": "87890532", + "metadata": {}, + "source": [ + "## Citations\n", + "\n", + "[1] Liu Y, Pan W. Spiking Neural-Networks-Based Data-Driven Control. Electronics. 2023; 12(2):310. https://doi.org/10.3390/electronics12020310 \n", + "\n", + "## Acknowledgements\n", + "\n", + "The authors would like to thank Prof. Wei Pan and Dr. Yuxiang Liu for kindly providing ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6b636d6", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "cart_pole", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -3039,7 +3233,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.8" + "version": "3.11.4" } }, "nbformat": 4, diff --git a/doc/tutorials/cart_pole_reinforcement_learning/synapse_test.ipynb b/doc/tutorials/cart_pole_reinforcement_learning/synapse_test.ipynb index 2add2e808..c70df73c5 100644 --- a/doc/tutorials/cart_pole_reinforcement_learning/synapse_test.ipynb +++ b/doc/tutorials/cart_pole_reinforcement_learning/synapse_test.ipynb @@ -2,15 +2,1264 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " -- N E S T --\n", + " Copyright (C) 2004 The NEST Initiative\n", + "\n", + " Version: 3.8.0-post0.dev0\n", + " Built: Dec 10 2024 12:04:47\n", + "\n", + " This program is provided AS IS and comes with\n", + " NO WARRANTY. See the file LICENSE for details.\n", + "\n", + " Problems or suggestions?\n", + " Visit https://www.nest-simulator.org\n", + "\n", + " Type 'nest.help()' to find out more about NEST.\n", + "\n", + "\n", + " -- N E S T --\n", + " Copyright (C) 2004 The NEST Initiative\n", + "\n", + " Version: 3.8.0-post0.dev0\n", + " Built: Dec 10 2024 12:04:47\n", + "\n", + " This program is provided AS IS and comes with\n", + " NO WARRANTY. See the file LICENSE for details.\n", + "\n", + " Problems or suggestions?\n", + " Visit https://www.nest-simulator.org\n", + "\n", + " Type 'nest.help()' to find out more about NEST.\n", + "\n", + "[15,ignore_and_fire_neuron_nestml, WARNING, [35:34;35:58]]: Model contains a call to fixed-timestep functions (``resolution()`` and/or ``steps()``). This restricts the model to being compatible only with fixed-timestep simulators. Consider eliminating ``resolution()`` and ``steps()`` from the model, and using ``timestep()`` instead.\n", + "CMake Warning (dev) at CMakeLists.txt:93 (project):\n", + " cmake_minimum_required() should be called prior to this top-level project()\n", + " call. Please see the cmake-commands(7) manual for usage documentation of\n", + " both commands.\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\n", + "-- The CXX compiler identification is GNU 12.3.0\n", + "-- Detecting CXX compiler ABI info\n", + "-- Detecting CXX compiler ABI info - done\n", + "-- Check for working CXX compiler: /usr/bin/c++ - skipped\n", + "-- Detecting CXX compile features\n", + "-- Detecting CXX compile features - done\n", + "\n", + "-------------------------------------------------------\n", + "nestml_338a9b110e204f319b59aebfa6283baf_module Configuration Summary\n", + "-------------------------------------------------------\n", + "\n", + "C++ compiler : /usr/bin/c++\n", + "Build static libs : OFF\n", + "C++ compiler flags : \n", + "NEST compiler flags : -std=c++17 -Wall -fopenmp -O2 -fdiagnostics-color=auto\n", + "NEST include dirs : -I/home/charl/julich/nest-simulator-install/include/nest -I/usr/include -I/usr/include -I/usr/include\n", + "NEST libraries flags : -L/home/charl/julich/nest-simulator-install/lib/nest -lnest -lsli /usr/lib/x86_64-linux-gnu/libltdl.so /usr/lib/x86_64-linux-gnu/libgsl.so /usr/lib/x86_64-linux-gnu/libgslcblas.so /usr/lib/gcc/x86_64-linux-gnu/12/libgomp.so /usr/lib/x86_64-linux-gnu/libpthread.a\n", + "\n", + "-------------------------------------------------------\n", + "\n", + "You can now build and install 'nestml_338a9b110e204f319b59aebfa6283baf_module' using\n", + " make\n", + " make install\n", + "\n", + "The library file libnestml_338a9b110e204f319b59aebfa6283baf_module.so will be installed to\n", + " /tmp/nestml_target_m91ieny9\n", + "The module can be loaded into NEST using\n", + " (nestml_338a9b110e204f319b59aebfa6283baf_module) Install (in SLI)\n", + " nest.Install(nestml_338a9b110e204f319b59aebfa6283baf_module) (in PyNEST)\n", + "\n", + "CMake Warning (dev) in CMakeLists.txt:\n", + " No cmake_minimum_required command is present. A line of code such as\n", + "\n", + " cmake_minimum_required(VERSION 3.26)\n", + "\n", + " should be added at the top of the file. The version specified may be lower\n", + " if you wish to support older CMake versions for this project. For more\n", + " information run \"cmake --help-policy CMP0000\".\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\n", + "-- Configuring done (0.5s)\n", + "-- Generating done (0.0s)\n", + "-- Build files have been written to: /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target\n", + "[ 66%] Building CXX object CMakeFiles/nestml_338a9b110e204f319b59aebfa6283baf_module_module.dir/nestml_338a9b110e204f319b59aebfa6283baf_module.o\n", + "[ 66%] Building CXX object CMakeFiles/nestml_338a9b110e204f319b59aebfa6283baf_module_module.dir/ignore_and_fire_neuron_nestml.o\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp: In member function ‘void ignore_and_fire_neuron_nestml::init_state_internal_()’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp:165:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 165 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp: In member function ‘void ignore_and_fire_neuron_nestml::recompute_internal_variables(bool)’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp:195:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 195 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp: In member function ‘virtual void ignore_and_fire_neuron_nestml::update(const nest::Time&, long int, long int)’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp:247:24: warning: comparison of integer expressions of different signedness: ‘long int’ and ‘const size_t’ {aka ‘const long unsigned int’} [-Wsign-compare]\n", + " 247 | for (long i = 0; i < NUM_SPIKE_RECEPTORS; ++i)\n", + " | ~~^~~~~~~~~~~~~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp:238:10: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 238 | auto get_t = [origin, lag](){ return nest::Time( nest::Time::step( origin.get_steps() + lag + 1) ).get_ms(); };\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/ignore_and_fire_neuron_nestml.cpp:232:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 232 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "[100%] Linking CXX shared module nestml_338a9b110e204f319b59aebfa6283baf_module.so\n", + "[100%] Built target nestml_338a9b110e204f319b59aebfa6283baf_module_module\n", + "[100%] Built target nestml_338a9b110e204f319b59aebfa6283baf_module_module\n", + "Install the project...\n", + "-- Install configuration: \"\"\n", + "-- Installing: /tmp/nestml_target_m91ieny9/nestml_338a9b110e204f319b59aebfa6283baf_module.so\n", + "[1,GLOBAL, INFO]: List of files that will be processed:\n", + "[2,GLOBAL, INFO]: /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/iaf_psc_exp_neuron.nestml\n", + "[3,GLOBAL, INFO]: /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/neuromodulated_stdp_synapse.nestml\n", + "[4,GLOBAL, INFO]: Target platform code will be generated in directory: '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target'\n", + "[5,GLOBAL, INFO]: Target platform code will be installed in directory: '/tmp/nestml_target_xi9ld_gb'\n", + "\n", + " -- N E S T --\n", + " Copyright (C) 2004 The NEST Initiative\n", + "\n", + " Version: 3.8.0-post0.dev0\n", + " Built: Dec 10 2024 12:04:47\n", + "\n", + " This program is provided AS IS and comes with\n", + " NO WARRANTY. See the file LICENSE for details.\n", + "\n", + " Problems or suggestions?\n", + " Visit https://www.nest-simulator.org\n", + "\n", + " Type 'nest.help()' to find out more about NEST.\n", + "\n", + "[6,GLOBAL, INFO]: The NEST Simulator version was automatically detected as: master\n", + "[7,GLOBAL, INFO]: Given template root path is not an absolute path. Creating the absolute path with default templates directory '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/pynestml/codegeneration/resources_nest/point_neuron'\n", + "[8,GLOBAL, INFO]: Given template root path is not an absolute path. Creating the absolute path with default templates directory '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/pynestml/codegeneration/resources_nest/point_neuron'\n", + "[9,GLOBAL, INFO]: Given template root path is not an absolute path. Creating the absolute path with default templates directory '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/pynestml/codegeneration/resources_nest/point_neuron'\n", + "[10,GLOBAL, INFO]: The NEST Simulator installation path was automatically detected as: /home/charl/julich/nest-simulator-install\n", + "[11,GLOBAL, INFO]: Start processing '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/iaf_psc_exp_neuron.nestml'!\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[12,iaf_psc_exp_neuron_nestml, INFO, [39:19;39:19]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[13,iaf_psc_exp_neuron_nestml, INFO, [42:17;42:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[14,iaf_psc_exp_neuron_nestml, INFO, [55:15;55:32]]: Implicit casting from (compatible) type '1 / s buffer' to 'real'.\n", + "[15,GLOBAL, INFO]: Start processing '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/neuromodulated_stdp_synapse.nestml'!\n", + "[16,neuromodulated_stdp_synapse_nestml, INFO, [10:17;10:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[17,neuromodulated_stdp_synapse_nestml, INFO, [20:21;20:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[18,neuromodulated_stdp_synapse_nestml, INFO, [21:23;21:23]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[19,neuromodulated_stdp_synapse_nestml, INFO, [22:24;22:24]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[20,neuromodulated_stdp_synapse_nestml, INFO, [38:22;38:22]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[21,neuromodulated_stdp_synapse_nestml, INFO, [45:21;45:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[22,iaf_psc_exp_neuron_nestml, WARNING, [42:8;42:17]]: Variable 's' has the same name as a physical unit!\n", + "[23,iaf_psc_exp_neuron_nestml, WARNING, [28:16;28:42]]: Implicit casting from (compatible) type 'mV' to 'real'.\n", + "[24,iaf_psc_exp_neuron_nestml, WARNING, [28:16;28:48]]: Implicit casting from (compatible) type 'mV' to 'real buffer'.\n", + "[25,iaf_psc_exp_neuron_nestml, INFO, [39:19;39:19]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[26,iaf_psc_exp_neuron_nestml, INFO, [42:17;42:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[27,iaf_psc_exp_neuron_nestml, INFO, [55:15;55:32]]: Implicit casting from (compatible) type '1 / s buffer' to 'real'.\n", + "[28,neuromodulated_stdp_synapse_nestml, WARNING, [16:8;16:17]]: Variable 'd' has the same name as a physical unit!\n", + "[29,neuromodulated_stdp_synapse_nestml, INFO, [10:17;10:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[30,neuromodulated_stdp_synapse_nestml, INFO, [20:21;20:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[31,neuromodulated_stdp_synapse_nestml, INFO, [21:23;21:23]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[32,neuromodulated_stdp_synapse_nestml, INFO, [22:24;22:24]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[33,neuromodulated_stdp_synapse_nestml, INFO, [38:22;38:22]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[34,neuromodulated_stdp_synapse_nestml, INFO, [45:21;45:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[35,GLOBAL, INFO]: State variables that will be moved from synapse to neuron: ['post_trace']\n", + "[36,GLOBAL, INFO]: Parameters that will be copied from synapse to neuron: ['tau_tr_post']\n", + "[37,GLOBAL, INFO]: Synaptic state variables moved to neuron that will need buffering: []\n", + "[38,GLOBAL, INFO]: Moving state var defining equation(s) post_trace\n", + "[39,GLOBAL, INFO]: Moving state variables for equation(s) post_trace\n", + "[40,GLOBAL, INFO]: Moving definition of post_trace from synapse to neuron\n", + "[41,GLOBAL, INFO]: \tMoving statement post_trace += 1\n", + "[42,GLOBAL, INFO]: In synapse: replacing ``continuous`` type input ports that are connected to postsynaptic neuron with external variable references\n", + "[43,GLOBAL, INFO]: Copying parameters from synapse to neuron...\n", + "[44,GLOBAL, INFO]: Copying definition of tau_tr_post from synapse to neuron\n", + "[45,GLOBAL, INFO]: Adding suffix to variables in spike updates\n", + "[46,GLOBAL, INFO]: In synapse: replacing variables with suffixed external variable references\n", + "[47,GLOBAL, INFO]: \t• Replacing variable post_trace\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:Analysing input:\n", + "INFO:{\n", + " \"dynamics\": [\n", + " {\n", + " \"expression\": \"g_e' = (-g_e) / tau_g\",\n", + " \"initial_values\": {\n", + " \"g_e\": \"0.0\"\n", + " }\n", + " },\n", + " {\n", + " \"expression\": \"V_m' = (g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\",\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\"\n", + " }\n", + " }\n", + " ],\n", + " \"options\": {\n", + " \"output_timestep_symbol\": \"__h\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"(-74)\",\n", + " \"I_e\": \"0\",\n", + " \"V_reset\": \"(-60)\",\n", + " \"V_th\": \"(-54)\",\n", + " \"s\": \"1000\",\n", + " \"tau_g\": \"5\",\n", + " \"tau_m\": \"10\"\n", + " }\n", + "}\n", + "INFO:Processing global options...\n", + "INFO:Processing input shapes...\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0.0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [V_m])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m\n", + "DEBUG:\tnonlinear term: E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m, nonlin_term = E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n", + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "INFO:All known variables: [g_e, V_m], all parameters used in ODEs: {tau_g, tau_m, E_e, I_e, E_l, I_stim}\n", + "INFO:No numerical value specified for parameter \"I_stim\"\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m, g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [g_e, V_m, g_e, V_m])\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m + I_stim/tau_m, nonlin_term = E_e*g_e/tau_m - V_m*g_e/tau_m\n", + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols Matrix([[g_e], [V_m]]))\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols Matrix([[g_e], [V_m]]))\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[48,GLOBAL, INFO]: Successfully constructed neuron-synapse pair iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml, neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml\n", + "[49,GLOBAL, INFO]: Analysing/transforming model 'iaf_psc_exp_neuron_nestml'\n", + "[50,iaf_psc_exp_neuron_nestml, INFO, [20:0;60:0]]: Starts processing of the model 'iaf_psc_exp_neuron_nestml'\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e], [V_m]]), A = Matrix([[-1/tau_g, 0], [E_e/tau_m, -1/tau_m]]), b = Matrix([[0], [E_l/tau_m + I_e/tau_m + I_stim/tau_m]]), c = Matrix([[0], [-V_m*g_e/tau_m]])\n", + "INFO:Finding analytically solvable equations...\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph.dot']\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols [g_e, V_m])\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable_before_propagated.dot']\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable.dot']\n", + "INFO:Generating propagators for the following symbols: g_e\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e]]), A = Matrix([[-1/tau_g]]), b = Matrix([[0]]), c = Matrix([[0]])\n", + "DEBUG:System of equations:\n", + "DEBUG:x = Matrix([[g_e]])\n", + "DEBUG:A = Matrix([[-1/tau_g]])\n", + "DEBUG:b = Matrix([[0]])\n", + "DEBUG:c = Matrix([[0]])\n", + "INFO:update_expr[g_e] = __P__g_e__g_e*g_e\n", + "INFO:Generating numerical solver for the following symbols: V_m\n", + "DEBUG:Initializing system of shapes with x = Matrix([[V_m]]), A = Matrix([[-1/tau_m]]), b = Matrix([[E_l/tau_m + I_e/tau_m + I_stim/tau_m]]), c = Matrix([[E_e*g_e/tau_m - V_m*g_e/tau_m]])\n", + "WARNING:Not preserving expression for variable \"g_e\" as it is solved by propagator solver\n", + "INFO:Preserving expression for variable \"V_m\"\n", + "INFO:In ode-toolbox: returning outdict = \n", + "INFO:[\n", + " {\n", + " \"initial_values\": {\n", + " \"g_e\": \"0.0\"\n", + " },\n", + " \"parameters\": {\n", + " \"tau_g\": \"5.00000000000000\"\n", + " },\n", + " \"propagators\": {\n", + " \"__P__g_e__g_e\": \"exp(-__h/tau_g)\"\n", + " },\n", + " \"solver\": \"analytical\",\n", + " \"state_variables\": [\n", + " \"g_e\"\n", + " ],\n", + " \"update_expressions\": {\n", + " \"g_e\": \"__P__g_e__g_e*g_e\"\n", + " }\n", + " },\n", + " {\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"-74.0000000000000\",\n", + " \"I_e\": \"0\",\n", + " \"tau_m\": \"10.0000000000000\"\n", + " },\n", + " \"solver\": \"numeric\",\n", + " \"state_variables\": [\n", + " \"V_m\"\n", + " ],\n", + " \"update_expressions\": {\n", + " \"V_m\": \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + " }\n", + " }\n", + "]\n", + "INFO:Analysing input:\n", + "INFO:{\n", + " \"dynamics\": [\n", + " {\n", + " \"expression\": \"g_e' = (-g_e) / tau_g\",\n", + " \"initial_values\": {\n", + " \"g_e\": \"0.0\"\n", + " }\n", + " },\n", + " {\n", + " \"expression\": \"V_m' = (g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\",\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\"\n", + " }\n", + " }\n", + " ],\n", + " \"options\": {\n", + " \"output_timestep_symbol\": \"__h\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"(-74)\",\n", + " \"I_e\": \"0\",\n", + " \"V_reset\": \"(-60)\",\n", + " \"V_th\": \"(-54)\",\n", + " \"s\": \"1000\",\n", + " \"tau_g\": \"5\",\n", + " \"tau_m\": \"10\"\n", + " }\n", + "}\n", + "INFO:Processing global options...\n", + "INFO:Processing input shapes...\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0.0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [V_m])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m\n", + "DEBUG:\tnonlinear term: E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m, nonlin_term = E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n", + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "INFO:All known variables: [g_e, V_m], all parameters used in ODEs: {tau_g, tau_m, E_e, I_e, E_l, I_stim}\n", + "INFO:No numerical value specified for parameter \"I_stim\"\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m, g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [g_e, V_m, g_e, V_m])\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m + I_stim/tau_m, nonlin_term = E_e*g_e/tau_m - V_m*g_e/tau_m\n", + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols Matrix([[g_e], [V_m]]))\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols Matrix([[g_e], [V_m]]))\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e], [V_m]]), A = Matrix([[-1/tau_g, 0], [E_e/tau_m, -1/tau_m]]), b = Matrix([[0], [E_l/tau_m + I_e/tau_m + I_stim/tau_m]]), c = Matrix([[0], [-V_m*g_e/tau_m]])\n", + "INFO:Finding analytically solvable equations...\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph.dot']\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols [g_e, V_m])\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable_before_propagated.dot']\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable.dot']\n", + "INFO:Generating numerical solver for the following symbols: V_m, g_e\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e], [V_m]]), A = Matrix([[-1/tau_g, 0], [E_e/tau_m, -1/tau_m]]), b = Matrix([[0], [E_l/tau_m + I_e/tau_m + I_stim/tau_m]]), c = Matrix([[0], [-V_m*g_e/tau_m]])\n", + "INFO:Preserving expression for variable \"g_e\"\n", + "INFO:Preserving expression for variable \"V_m\"\n", + "INFO:In ode-toolbox: returning outdict = \n", + "INFO:[\n", + " {\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\",\n", + " \"g_e\": \"0.0\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"-74.0000000000000\",\n", + " \"I_e\": \"0\",\n", + " \"tau_g\": \"5.00000000000000\",\n", + " \"tau_m\": \"10.0000000000000\"\n", + " },\n", + " \"solver\": \"numeric\",\n", + " \"state_variables\": [\n", + " \"g_e\",\n", + " \"V_m\"\n", + " ],\n", + " \"update_expressions\": {\n", + " \"V_m\": \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\",\n", + " \"g_e\": \"(-g_e) / tau_g\"\n", + " }\n", + " }\n", + "]\n", + "INFO:Analysing input:\n", + "INFO:{\n", + " \"dynamics\": [\n", + " {\n", + " \"expression\": \"g_e' = (-g_e) / tau_g\",\n", + " \"initial_values\": {\n", + " \"g_e\": \"0.0\"\n", + " }\n", + " },\n", + " {\n", + " \"expression\": \"V_m' = (g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\",\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\"\n", + " }\n", + " },\n", + " {\n", + " \"expression\": \"post_trace__for_neuromodulated_stdp_synapse_nestml' = (-post_trace__for_neuromodulated_stdp_synapse_nestml) / tau_tr_post__for_neuromodulated_stdp_synapse_nestml\",\n", + " \"initial_values\": {\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\": \"0.0\"\n", + " }\n", + " }\n", + " ],\n", + " \"options\": {\n", + " \"output_timestep_symbol\": \"__h\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"(-74)\",\n", + " \"I_e\": \"0\",\n", + " \"V_reset\": \"(-60)\",\n", + " \"V_th\": \"(-54)\",\n", + " \"s\": \"1000\",\n", + " \"tau_g\": \"5\",\n", + " \"tau_m\": \"10\",\n", + " \"tau_tr_post__for_neuromodulated_stdp_synapse_nestml\": \"20\"\n", + " }\n", + "}\n", + "INFO:Processing global options...\n", + "INFO:Processing input shapes...\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0.0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [V_m])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m\n", + "DEBUG:\tnonlinear term: E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m, nonlin_term = E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[51,iaf_psc_exp_neuron_nestml, WARNING, [42:8;42:17]]: Variable 's' has the same name as a physical unit!\n", + "[52,iaf_psc_exp_neuron_nestml, INFO, [39:19;39:19]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[53,iaf_psc_exp_neuron_nestml, INFO, [42:17;42:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[54,iaf_psc_exp_neuron_nestml, INFO, [55:15;55:32]]: Implicit casting from (compatible) type '1 / s buffer' to 'real'.\n", + "[55,GLOBAL, INFO]: Analysing/transforming model 'iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml'\n", + "[56,iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml, INFO, [20:0;60:0]]: Starts processing of the model 'iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml'\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "INFO:\n", + "Processing differential-equation form shape post_trace__for_neuromodulated_stdp_synapse_nestml with defining expression = \"(-post_trace__for_neuromodulated_stdp_synapse_nestml) / tau_tr_post__for_neuromodulated_stdp_synapse_nestml\"\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols [post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol post_trace__for_neuromodulated_stdp_synapse_nestml, derivative_factors = [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml], inhom_term = 0.0, nonlin_term = 0.0\n", + "INFO:\tReturning shape: Shape \"post_trace__for_neuromodulated_stdp_synapse_nestml\" of order 1\n", + "INFO:Shape post_trace__for_neuromodulated_stdp_synapse_nestml: reconstituting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml\n", + "INFO:All known variables: [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml], all parameters used in ODEs: {tau_g, tau_m, tau_tr_post__for_neuromodulated_stdp_synapse_nestml, E_e, I_e, E_l, I_stim}\n", + "INFO:No numerical value specified for parameter \"I_stim\"\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml, g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml, g_e, V_m])\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m + I_stim/tau_m, nonlin_term = E_e*g_e/tau_m - V_m*g_e/tau_m\n", + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:\n", + "Processing differential-equation form shape post_trace__for_neuromodulated_stdp_synapse_nestml with defining expression = \"(-post_trace__for_neuromodulated_stdp_synapse_nestml) / tau_tr_post__for_neuromodulated_stdp_synapse_nestml\"\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml, g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[0], [0], [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml], [0], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol post_trace__for_neuromodulated_stdp_synapse_nestml, derivative_factors = [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml], inhom_term = 0.0, nonlin_term = 0\n", + "INFO:\tReturning shape: Shape \"post_trace__for_neuromodulated_stdp_synapse_nestml\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]))\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]))\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "INFO:Shape post_trace__for_neuromodulated_stdp_synapse_nestml: reconstituting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]))\n", + "DEBUG:\tlinear factors: Matrix([[0], [0], [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]), A = Matrix([[-1/tau_g, 0, 0], [E_e/tau_m, -1/tau_m, 0], [0, 0, -1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]]), b = Matrix([[0], [E_l/tau_m + I_e/tau_m + I_stim/tau_m], [0]]), c = Matrix([[0], [-V_m*g_e/tau_m], [0]])\n", + "INFO:Finding analytically solvable equations...\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph.dot']\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "INFO:Shape post_trace__for_neuromodulated_stdp_synapse_nestml: reconstituting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[0], [0], [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable_before_propagated.dot']\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable.dot']\n", + "INFO:Generating propagators for the following symbols: g_e, post_trace__for_neuromodulated_stdp_synapse_nestml\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e], [post_trace__for_neuromodulated_stdp_synapse_nestml]]), A = Matrix([[-1/tau_g, 0], [0, -1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]]), b = Matrix([[0], [0]]), c = Matrix([[0], [0]])\n", + "DEBUG:System of equations:\n", + "DEBUG:x = Matrix([[g_e], [post_trace__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:A = Matrix([\n", + "[-1/tau_g, 0],\n", + "[ 0, -1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:b = Matrix([[0], [0]])\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "DEBUG:c = Matrix([[0], [0]])\n", + "INFO:update_expr[g_e] = __P__g_e__g_e*g_e\n", + "INFO:update_expr[post_trace__for_neuromodulated_stdp_synapse_nestml] = __P__post_trace__for_neuromodulated_stdp_synapse_nestml__post_trace__for_neuromodulated_stdp_synapse_nestml*post_trace__for_neuromodulated_stdp_synapse_nestml\n", + "INFO:Generating numerical solver for the following symbols: V_m\n", + "DEBUG:Initializing system of shapes with x = Matrix([[V_m]]), A = Matrix([[-1/tau_m]]), b = Matrix([[E_l/tau_m + I_e/tau_m + I_stim/tau_m]]), c = Matrix([[E_e*g_e/tau_m - V_m*g_e/tau_m]])\n", + "WARNING:Not preserving expression for variable \"g_e\" as it is solved by propagator solver\n", + "WARNING:Not preserving expression for variable \"post_trace__for_neuromodulated_stdp_synapse_nestml\" as it is solved by propagator solver\n", + "INFO:Preserving expression for variable \"V_m\"\n", + "INFO:In ode-toolbox: returning outdict = \n", + "INFO:[\n", + " {\n", + " \"initial_values\": {\n", + " \"g_e\": \"0.0\",\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\": \"0.0\"\n", + " },\n", + " \"parameters\": {\n", + " \"tau_g\": \"5.00000000000000\",\n", + " \"tau_tr_post__for_neuromodulated_stdp_synapse_nestml\": \"20.0000000000000\"\n", + " },\n", + " \"propagators\": {\n", + " \"__P__g_e__g_e\": \"exp(-__h/tau_g)\",\n", + " \"__P__post_trace__for_neuromodulated_stdp_synapse_nestml__post_trace__for_neuromodulated_stdp_synapse_nestml\": \"exp(-__h/tau_tr_post__for_neuromodulated_stdp_synapse_nestml)\"\n", + " },\n", + " \"solver\": \"analytical\",\n", + " \"state_variables\": [\n", + " \"g_e\",\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\"\n", + " ],\n", + " \"update_expressions\": {\n", + " \"g_e\": \"__P__g_e__g_e*g_e\",\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\": \"__P__post_trace__for_neuromodulated_stdp_synapse_nestml__post_trace__for_neuromodulated_stdp_synapse_nestml*post_trace__for_neuromodulated_stdp_synapse_nestml\"\n", + " }\n", + " },\n", + " {\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"-74.0000000000000\",\n", + " \"I_e\": \"0\",\n", + " \"tau_m\": \"10.0000000000000\"\n", + " },\n", + " \"solver\": \"numeric\",\n", + " \"state_variables\": [\n", + " \"V_m\"\n", + " ],\n", + " \"update_expressions\": {\n", + " \"V_m\": \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + " }\n", + " }\n", + "]\n", + "INFO:Analysing input:\n", + "INFO:{\n", + " \"dynamics\": [\n", + " {\n", + " \"expression\": \"g_e' = (-g_e) / tau_g\",\n", + " \"initial_values\": {\n", + " \"g_e\": \"0.0\"\n", + " }\n", + " },\n", + " {\n", + " \"expression\": \"V_m' = (g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\",\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\"\n", + " }\n", + " },\n", + " {\n", + " \"expression\": \"post_trace__for_neuromodulated_stdp_synapse_nestml' = (-post_trace__for_neuromodulated_stdp_synapse_nestml) / tau_tr_post__for_neuromodulated_stdp_synapse_nestml\",\n", + " \"initial_values\": {\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\": \"0.0\"\n", + " }\n", + " }\n", + " ],\n", + " \"options\": {\n", + " \"output_timestep_symbol\": \"__h\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"(-74)\",\n", + " \"I_e\": \"0\",\n", + " \"V_reset\": \"(-60)\",\n", + " \"V_th\": \"(-54)\",\n", + " \"s\": \"1000\",\n", + " \"tau_g\": \"5\",\n", + " \"tau_m\": \"10\",\n", + " \"tau_tr_post__for_neuromodulated_stdp_synapse_nestml\": \"20\"\n", + " }\n", + "}\n", + "INFO:Processing global options...\n", + "INFO:Processing input shapes...\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0.0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [V_m])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_m]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m\n", + "DEBUG:\tnonlinear term: E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m, nonlin_term = E_e*g_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m\n", + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "INFO:\n", + "Processing differential-equation form shape post_trace__for_neuromodulated_stdp_synapse_nestml with defining expression = \"(-post_trace__for_neuromodulated_stdp_synapse_nestml) / tau_tr_post__for_neuromodulated_stdp_synapse_nestml\"\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols [post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol post_trace__for_neuromodulated_stdp_synapse_nestml, derivative_factors = [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml], inhom_term = 0.0, nonlin_term = 0.0\n", + "INFO:\tReturning shape: Shape \"post_trace__for_neuromodulated_stdp_synapse_nestml\" of order 1\n", + "INFO:Shape post_trace__for_neuromodulated_stdp_synapse_nestml: reconstituting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml\n", + "INFO:All known variables: [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml], all parameters used in ODEs: {tau_g, tau_m, tau_tr_post__for_neuromodulated_stdp_synapse_nestml, E_e, I_e, E_l, I_stim}\n", + "INFO:No numerical value specified for parameter \"I_stim\"\n", + "INFO:\n", + "Processing differential-equation form shape g_e with defining expression = \"(-g_e) / tau_g\"\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml, g_e])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol g_e, derivative_factors = [-1/tau_g], inhom_term = 0.0, nonlin_term = 0\n", + "INFO:\tReturning shape: Shape \"g_e\" of order 1\n", + "INFO:\n", + "Processing differential-equation form shape V_m with defining expression = \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\"\n", + "DEBUG:Splitting expression (E_l + I_e + I_stim - V_m + g_e*(E_e - V_m))/tau_m (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml, g_e, V_m])\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "DEBUG:Created Shape with symbol V_m, derivative_factors = [-1/tau_m], inhom_term = E_l/tau_m + I_e/tau_m + I_stim/tau_m, nonlin_term = E_e*g_e/tau_m - V_m*g_e/tau_m\n", + "INFO:\tReturning shape: Shape \"V_m\" of order 1\n", + "INFO:\n", + "Processing differential-equation form shape post_trace__for_neuromodulated_stdp_synapse_nestml with defining expression = \"(-post_trace__for_neuromodulated_stdp_synapse_nestml) / tau_tr_post__for_neuromodulated_stdp_synapse_nestml\"\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml, g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[0], [0], [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml], [0], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol post_trace__for_neuromodulated_stdp_synapse_nestml, derivative_factors = [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml], inhom_term = 0.0, nonlin_term = 0\n", + "INFO:\tReturning shape: Shape \"post_trace__for_neuromodulated_stdp_synapse_nestml\" of order 1\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "DEBUG:Splitting expression -g_e/tau_g (symbols Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]))\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]))\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "INFO:Shape post_trace__for_neuromodulated_stdp_synapse_nestml: reconstituting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]))\n", + "DEBUG:\tlinear factors: Matrix([[0], [0], [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]), A = Matrix([[-1/tau_g, 0, 0], [E_e/tau_m, -1/tau_m, 0], [0, 0, -1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]]), b = Matrix([[0], [E_l/tau_m + I_e/tau_m + I_stim/tau_m], [0]]), c = Matrix([[0], [-V_m*g_e/tau_m], [0]])\n", + "INFO:Finding analytically solvable equations...\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph.dot']\n", + "INFO:Shape g_e: reconstituting expression -g_e/tau_g\n", + "DEBUG:Splitting expression -g_e/tau_g (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_g], [0], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Shape V_m: reconstituting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m\n", + "DEBUG:Splitting expression E_e*g_e/tau_m + E_l/tau_m + I_e/tau_m + I_stim/tau_m - V_m*g_e/tau_m - V_m/tau_m (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[E_e/tau_m], [-1/tau_m], [0]])\n", + "DEBUG:\tinhomogeneous term: E_l/tau_m + I_e/tau_m + I_stim/tau_m\n", + "DEBUG:\tnonlinear term: -V_m*g_e/tau_m\n", + "INFO:Shape post_trace__for_neuromodulated_stdp_synapse_nestml: reconstituting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml\n", + "DEBUG:Splitting expression -post_trace__for_neuromodulated_stdp_synapse_nestml/tau_tr_post__for_neuromodulated_stdp_synapse_nestml (symbols [g_e, V_m, post_trace__for_neuromodulated_stdp_synapse_nestml])\n", + "DEBUG:\tlinear factors: Matrix([[0], [0], [-1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable_before_propagated.dot']\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable.dot']\n", + "INFO:Generating numerical solver for the following symbols: post_trace__for_neuromodulated_stdp_synapse_nestml, V_m, g_e\n", + "DEBUG:Initializing system of shapes with x = Matrix([[g_e], [V_m], [post_trace__for_neuromodulated_stdp_synapse_nestml]]), A = Matrix([[-1/tau_g, 0, 0], [E_e/tau_m, -1/tau_m, 0], [0, 0, -1/tau_tr_post__for_neuromodulated_stdp_synapse_nestml]]), b = Matrix([[0], [E_l/tau_m + I_e/tau_m + I_stim/tau_m], [0]]), c = Matrix([[0], [-V_m*g_e/tau_m], [0]])\n", + "INFO:Preserving expression for variable \"g_e\"\n", + "INFO:Preserving expression for variable \"V_m\"\n", + "INFO:Preserving expression for variable \"post_trace__for_neuromodulated_stdp_synapse_nestml\"\n", + "INFO:In ode-toolbox: returning outdict = \n", + "INFO:[\n", + " {\n", + " \"initial_values\": {\n", + " \"V_m\": \"E_l\",\n", + " \"g_e\": \"0.0\",\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\": \"0.0\"\n", + " },\n", + " \"parameters\": {\n", + " \"E_e\": \"0\",\n", + " \"E_l\": \"-74.0000000000000\",\n", + " \"I_e\": \"0\",\n", + " \"tau_g\": \"5.00000000000000\",\n", + " \"tau_m\": \"10.0000000000000\",\n", + " \"tau_tr_post__for_neuromodulated_stdp_synapse_nestml\": \"20.0000000000000\"\n", + " },\n", + " \"solver\": \"numeric\",\n", + " \"state_variables\": [\n", + " \"g_e\",\n", + " \"V_m\",\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\"\n", + " ],\n", + " \"update_expressions\": {\n", + " \"V_m\": \"(g_e * (E_e - V_m) + E_l - V_m + I_e + I_stim) / tau_m\",\n", + " \"g_e\": \"(-g_e) / tau_g\",\n", + " \"post_trace__for_neuromodulated_stdp_synapse_nestml\": \"(-post_trace__for_neuromodulated_stdp_synapse_nestml) / tau_tr_post__for_neuromodulated_stdp_synapse_nestml\"\n", + " }\n", + " }\n", + "]\n", + "INFO:Analysing input:\n", + "INFO:{\n", + " \"dynamics\": [\n", + " {\n", + " \"expression\": \"pre_trace' = (-pre_trace) / tau_tr_pre\",\n", + " \"initial_values\": {\n", + " \"pre_trace\": \"0.0\"\n", + " }\n", + " }\n", + " ],\n", + " \"options\": {\n", + " \"output_timestep_symbol\": \"__h\"\n", + " },\n", + " \"parameters\": {\n", + " \"Wmax\": \"100.0\",\n", + " \"Wmin\": \"0.0\",\n", + " \"alpha\": \"1\",\n", + " \"d\": \"1\",\n", + " \"lambda\": \"0.01\",\n", + " \"mu_minus\": \"1\",\n", + " \"mu_plus\": \"1\",\n", + " \"n\": \"0.0\",\n", + " \"tau_tr_post\": \"20\",\n", + " \"tau_tr_pre\": \"20\"\n", + " }\n", + "}\n", + "INFO:Processing global options...\n", + "INFO:Processing input shapes...\n", + "INFO:\n", + "Processing differential-equation form shape pre_trace with defining expression = \"(-pre_trace) / tau_tr_pre\"\n", + "DEBUG:Splitting expression -pre_trace/tau_tr_pre (symbols [pre_trace])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_tr_pre]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol pre_trace, derivative_factors = [-1/tau_tr_pre], inhom_term = 0.0, nonlin_term = 0.0\n", + "INFO:\tReturning shape: Shape \"pre_trace\" of order 1\n", + "INFO:Shape pre_trace: reconstituting expression -pre_trace/tau_tr_pre\n", + "INFO:All known variables: [pre_trace], all parameters used in ODEs: {tau_tr_pre}\n", + "INFO:\n", + "Processing differential-equation form shape pre_trace with defining expression = \"(-pre_trace) / tau_tr_pre\"\n", + "DEBUG:Splitting expression -pre_trace/tau_tr_pre (symbols [pre_trace, pre_trace])\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[57,iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml, WARNING, [42:8;42:17]]: Variable 's' has the same name as a physical unit!\n", + "[58,iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml, INFO, [39:19;39:19]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[59,iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml, INFO, [42:17;42:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[60,iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml, INFO, [55:15;55:32]]: Implicit casting from (compatible) type '1 / s buffer' to 'real'.\n", + "[61,GLOBAL, INFO]: Analysing/transforming synapse neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.\n", + "[62,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [8:0;55:0]]: Starts processing of the model 'neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml'\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "DEBUG:\tlinear factors: Matrix([[-1/tau_tr_pre], [0]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Created Shape with symbol pre_trace, derivative_factors = [-1/tau_tr_pre], inhom_term = 0.0, nonlin_term = 0\n", + "INFO:\tReturning shape: Shape \"pre_trace\" of order 1\n", + "INFO:Shape pre_trace: reconstituting expression -pre_trace/tau_tr_pre\n", + "DEBUG:Splitting expression -pre_trace/tau_tr_pre (symbols Matrix([[pre_trace]]))\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_tr_pre]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "DEBUG:Initializing system of shapes with x = Matrix([[pre_trace]]), A = Matrix([[-1/tau_tr_pre]]), b = Matrix([[0]]), c = Matrix([[0]])\n", + "INFO:Finding analytically solvable equations...\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph.dot']\n", + "INFO:Shape pre_trace: reconstituting expression -pre_trace/tau_tr_pre\n", + "DEBUG:Splitting expression -pre_trace/tau_tr_pre (symbols [pre_trace])\n", + "DEBUG:\tlinear factors: Matrix([[-1/tau_tr_pre]])\n", + "DEBUG:\tinhomogeneous term: 0.0\n", + "DEBUG:\tnonlinear term: 0.0\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable_before_propagated.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable_before_propagated.dot']\n", + "INFO:Saving dependency graph plot to /tmp/ode_dependency_graph_analytically_solvable.dot\n", + "DEBUG:os.makedirs('/tmp')\n", + "DEBUG:write lines to '/tmp/ode_dependency_graph_analytically_solvable.dot'\n", + "DEBUG:run [PosixPath('dot'), '-Kdot', '-Tpdf', '-O', 'ode_dependency_graph_analytically_solvable.dot']\n", + "INFO:Generating propagators for the following symbols: pre_trace\n", + "DEBUG:Initializing system of shapes with x = Matrix([[pre_trace]]), A = Matrix([[-1/tau_tr_pre]]), b = Matrix([[0]]), c = Matrix([[0]])\n", + "DEBUG:System of equations:\n", + "DEBUG:x = Matrix([[pre_trace]])\n", + "DEBUG:A = Matrix([[-1/tau_tr_pre]])\n", + "DEBUG:b = Matrix([[0]])\n", + "DEBUG:c = Matrix([[0]])\n", + "INFO:update_expr[pre_trace] = __P__pre_trace__pre_trace*pre_trace\n", + "WARNING:Not preserving expression for variable \"pre_trace\" as it is solved by propagator solver\n", + "INFO:In ode-toolbox: returning outdict = \n", + "INFO:[\n", + " {\n", + " \"initial_values\": {\n", + " \"pre_trace\": \"0.0\"\n", + " },\n", + " \"parameters\": {\n", + " \"tau_tr_pre\": \"20.0000000000000\"\n", + " },\n", + " \"propagators\": {\n", + " \"__P__pre_trace__pre_trace\": \"exp(-__h/tau_tr_pre)\"\n", + " },\n", + " \"solver\": \"analytical\",\n", + " \"state_variables\": [\n", + " \"pre_trace\"\n", + " ],\n", + " \"update_expressions\": {\n", + " \"pre_trace\": \"__P__pre_trace__pre_trace*pre_trace\"\n", + " }\n", + " }\n", + "]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[63,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, WARNING, [16:8;16:17]]: Variable 'd' has the same name as a physical unit!\n", + "[64,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [10:17;10:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[65,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [20:21;20:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[66,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [21:23;21:23]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[67,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [22:24;22:24]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[68,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [45:21;45:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[69,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, WARNING, [16:8;16:17]]: Variable 'd' has the same name as a physical unit!\n", + "[70,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [10:17;10:17]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[71,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [20:21;20:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[72,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [21:23;21:23]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[73,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [22:24;22:24]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[74,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [45:21;45:21]]: Implicit casting from (compatible) type 'integer' to 'real'.\n", + "[75,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp\n", + "[76,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.h\n", + "[77,iaf_psc_exp_neuron_nestml, INFO, [20:0;60:0]]: Successfully generated code for the model: 'iaf_psc_exp_neuron_nestml' in: '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target' !\n", + "[78,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp\n", + "[79,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.h\n", + "[80,iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml, INFO, [20:0;60:0]]: Successfully generated code for the model: 'iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml' in: '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target' !\n", + "[81,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h\n", + "[82,neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml, INFO, [8:0;55:0]]: Successfully generated code for the model: 'neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml' in: '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target' !\n", + "[83,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/nestml_db7c0041c73544bfa402cce9b4bb3f38_module.cpp\n", + "[84,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/nestml_db7c0041c73544bfa402cce9b4bb3f38_module.h\n", + "[85,GLOBAL, INFO]: Rendering template /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/CMakeLists.txt\n", + "[86,GLOBAL, INFO]: Successfully generated NEST module code in '/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target' !\n", + "CMake Warning (dev) at CMakeLists.txt:95 (project):\n", + " cmake_minimum_required() should be called prior to this top-level project()\n", + " call. Please see the cmake-commands(7) manual for usage documentation of\n", + " both commands.\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\n", + "-- The CXX compiler identification is GNU 12.3.0\n", + "-- Detecting CXX compiler ABI info\n", + "-- Detecting CXX compiler ABI info - done\n", + "-- Check for working CXX compiler: /usr/bin/c++ - skipped\n", + "-- Detecting CXX compile features\n", + "-- Detecting CXX compile features - done\n", + "\n", + "-------------------------------------------------------\n", + "nestml_db7c0041c73544bfa402cce9b4bb3f38_module Configuration Summary\n", + "-------------------------------------------------------\n", + "\n", + "C++ compiler : /usr/bin/c++\n", + "Build static libs : OFF\n", + "C++ compiler flags : \n", + "NEST compiler flags : -std=c++17 -Wall -fopenmp -O2 -fdiagnostics-color=auto\n", + "NEST include dirs : -I/home/charl/julich/nest-simulator-install/include/nest -I/usr/include -I/usr/include -I/usr/include\n", + "NEST libraries flags : -L/home/charl/julich/nest-simulator-install/lib/nest -lnest -lsli /usr/lib/x86_64-linux-gnu/libltdl.so /usr/lib/x86_64-linux-gnu/libgsl.so /usr/lib/x86_64-linux-gnu/libgslcblas.so /usr/lib/gcc/x86_64-linux-gnu/12/libgomp.so /usr/lib/x86_64-linux-gnu/libpthread.a\n", + "\n", + "-------------------------------------------------------\n", + "\n", + "You can now build and install 'nestml_db7c0041c73544bfa402cce9b4bb3f38_module' using\n", + " make\n", + " make install\n", + "\n", + "The library file libnestml_db7c0041c73544bfa402cce9b4bb3f38_module.so will be installed to\n", + " /tmp/nestml_target_xi9ld_gb\n", + "The module can be loaded into NEST using\n", + " (nestml_db7c0041c73544bfa402cce9b4bb3f38_module) Install (in SLI)\n", + " nest.Install(nestml_db7c0041c73544bfa402cce9b4bb3f38_module) (in PyNEST)\n", + "\n", + "CMake Warning (dev) in CMakeLists.txt:\n", + " No cmake_minimum_required command is present. A line of code such as\n", + "\n", + " cmake_minimum_required(VERSION 3.26)\n", + "\n", + " should be added at the top of the file. The version specified may be lower\n", + " if you wish to support older CMake versions for this project. For more\n", + " information run \"cmake --help-policy CMP0000\".\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\n", + "-- Configuring done (0.5s)\n", + "-- Generating done (0.0s)\n", + "-- Build files have been written to: /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target\n", + "[ 25%] Building CXX object CMakeFiles/nestml_db7c0041c73544bfa402cce9b4bb3f38_module_module.dir/nestml_db7c0041c73544bfa402cce9b4bb3f38_module.o\n", + "[ 50%] Building CXX object CMakeFiles/nestml_db7c0041c73544bfa402cce9b4bb3f38_module_module.dir/iaf_psc_exp_neuron_nestml.o\n", + "[ 75%] Building CXX object CMakeFiles/nestml_db7c0041c73544bfa402cce9b4bb3f38_module_module.dir/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.o\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp: In member function ‘void iaf_psc_exp_neuron_nestml::init_state_internal_()’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp:191:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 191 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp: In member function ‘void iaf_psc_exp_neuron_nestml::recompute_internal_variables(bool)’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp:271:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 271 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp: In member function ‘virtual void iaf_psc_exp_neuron_nestml::update(const nest::Time&, long int, long int)’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp:335:24: warning: comparison of integer expressions of different signedness: ‘long int’ and ‘const size_t’ {aka ‘const long unsigned int’} [-Wsign-compare]\n", + " 335 | for (long i = 0; i < NUM_SPIKE_RECEPTORS; ++i)\n", + " | ~~^~~~~~~~~~~~~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp:326:10: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 326 | auto get_t = [origin, lag](){ return nest::Time( nest::Time::step( origin.get_steps() + lag + 1) ).get_ms(); };\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp:320:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 320 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp: In member function ‘void iaf_psc_exp_neuron_nestml::on_receive_block_spikes_in_port()’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml.cpp:494:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 494 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp: In member function ‘void iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml::init_state_internal_()’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp:201:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 201 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp: In member function ‘void iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml::recompute_internal_variables(bool)’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp:290:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 290 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp: In member function ‘virtual void iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml::update(const nest::Time&, long int, long int)’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp:371:24: warning: comparison of integer expressions of different signedness: ‘long int’ and ‘const size_t’ {aka ‘const long unsigned int’} [-Wsign-compare]\n", + " 371 | for (long i = 0; i < NUM_SPIKE_RECEPTORS; ++i)\n", + " | ~~^~~~~~~~~~~~~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp:362:10: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 362 | auto get_t = [origin, lag](){ return nest::Time( nest::Time::step( origin.get_steps() + lag + 1) ).get_ms(); };\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp:356:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 356 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp: In member function ‘void iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml::on_receive_block_spikes_in_port()’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml.cpp:533:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 533 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "In file included from /home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/nestml_db7c0041c73544bfa402cce9b4bb3f38_module.cpp:36:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml() [with targetidentifierT = nest::TargetIdentifierPtrRport]’:\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_model.h:164:25: required from ‘nest::GenericConnectorModel::GenericConnectorModel(std::string) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/model_manager_impl.h:62:5: required from ‘void nest::ModelManager::register_connection_model(const std::string&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/nest_impl.h:37:70: required from ‘void nest::register_connection_model(const std::string&) [with ConnectorModelT = neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:597:104: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:725:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 725 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘void nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::recompute_internal_variables() [with targetidentifierT = nest::TargetIdentifierPtrRport]’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:739:3: required from ‘nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml() [with targetidentifierT = nest::TargetIdentifierPtrRport]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_model.h:164:25: required from ‘nest::GenericConnectorModel::GenericConnectorModel(std::string) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/model_manager_impl.h:62:5: required from ‘void nest::ModelManager::register_connection_model(const std::string&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/nest_impl.h:37:70: required from ‘void nest::register_connection_model(const std::string&) [with ConnectorModelT = neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:597:104: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:713:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 713 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml() [with targetidentifierT = nest::TargetIdentifierIndex]’:\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_model.h:164:25: required from ‘nest::GenericConnectorModel::GenericConnectorModel(std::string) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/model_manager_impl.h:103:34: required from ‘void nest::ModelManager::register_specific_connection_model_(const std::string&) [with CompleteConnecionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/model_manager_impl.h:67:80: required from ‘void nest::ModelManager::register_connection_model(const std::string&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/nest_impl.h:37:70: required from ‘void nest::register_connection_model(const std::string&) [with ConnectorModelT = neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:597:104: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:725:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 725 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘void nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::recompute_internal_variables() [with targetidentifierT = nest::TargetIdentifierIndex]’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:739:3: required from ‘nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml() [with targetidentifierT = nest::TargetIdentifierIndex]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_model.h:164:25: required from ‘nest::GenericConnectorModel::GenericConnectorModel(std::string) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/model_manager_impl.h:103:34: required from ‘void nest::ModelManager::register_specific_connection_model_(const std::string&) [with CompleteConnecionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/model_manager_impl.h:67:80: required from ‘void nest::ModelManager::register_connection_model(const std::string&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/nest_impl.h:37:70: required from ‘void nest::register_connection_model(const std::string&) [with ConnectorModelT = neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; std::string = std::__cxx11::basic_string]’\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:597:104: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:713:16: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 713 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘bool nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::send(nest::Event&, size_t, const nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestmlCommonSynapseProperties&) [with targetidentifierT = nest::TargetIdentifierPtrRport; size_t = long unsigned int]’:\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:391:22: required from ‘void nest::Connector::send_to_all(size_t, const std::vector&, nest::Event&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; size_t = long unsigned int]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:383:3: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:504:14: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 504 | auto get_t = [t_hist_entry_ms](){ return t_hist_entry_ms; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:532:12: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 532 | auto get_t = [__t_spike](){ return __t_spike; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:572:12: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 572 | auto get_t = [__t_spike](){ return __t_spike; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:429:18: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 429 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:431:10: warning: variable ‘get_thread’ set but not used [-Wunused-but-set-variable]\n", + " 431 | auto get_thread = [tid]()\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘bool nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::send(nest::Event&, size_t, const nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestmlCommonSynapseProperties&) [with targetidentifierT = nest::TargetIdentifierIndex; size_t = long unsigned int]’:\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:391:22: required from ‘void nest::Connector::send_to_all(size_t, const std::vector&, nest::Event&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; size_t = long unsigned int]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:383:3: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:504:14: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 504 | auto get_t = [t_hist_entry_ms](){ return t_hist_entry_ms; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:532:12: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 532 | auto get_t = [__t_spike](){ return __t_spike; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:572:12: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 572 | auto get_t = [__t_spike](){ return __t_spike; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:429:18: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 429 | const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:431:10: warning: variable ‘get_thread’ set but not used [-Wunused-but-set-variable]\n", + " 431 | auto get_thread = [tid]()\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘void nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::update_internal_state_(double, double, const nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestmlCommonSynapseProperties&) [with targetidentifierT = nest::TargetIdentifierPtrRport]’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:499:9: required from ‘bool nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::send(nest::Event&, size_t, const nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestmlCommonSynapseProperties&) [with targetidentifierT = nest::TargetIdentifierPtrRport; size_t = long unsigned int]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:391:22: required from ‘void nest::Connector::send_to_all(size_t, const std::vector&, nest::Event&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; size_t = long unsigned int]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:383:3: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:789:18: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 789 | const double __timestep = timestep; // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:790:10: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 790 | auto get_t = [t_start](){ return t_start; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h: In instantiation of ‘void nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::update_internal_state_(double, double, const nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestmlCommonSynapseProperties&) [with targetidentifierT = nest::TargetIdentifierIndex]’:\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:499:9: required from ‘bool nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml::send(nest::Event&, size_t, const nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestmlCommonSynapseProperties&) [with targetidentifierT = nest::TargetIdentifierIndex; size_t = long unsigned int]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:391:22: required from ‘void nest::Connector::send_to_all(size_t, const std::vector&, nest::Event&) [with ConnectionT = nest::neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml; size_t = long unsigned int]’\n", + "/home/charl/julich/nest-simulator-install/include/nest/connector_base.h:383:3: required from here\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:789:18: warning: unused variable ‘__timestep’ [-Wunused-variable]\n", + " 789 | const double __timestep = timestep; // do not remove, this is necessary for the timestep() function\n", + " | ^~~~~~~~~~\n", + "/home/charl/julich/nestml-fork-AlexisWis-cart_pole_tutorial/nestml/doc/tutorials/cart_pole_reinforcement_learning/target/neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml.h:790:10: warning: variable ‘get_t’ set but not used [-Wunused-but-set-variable]\n", + " 790 | auto get_t = [t_start](){ return t_start; }; // do not remove, this is in case the predefined time variable ``t`` is used in the NESTML model\n", + " | ^~~~~\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[100%] Linking CXX shared module nestml_db7c0041c73544bfa402cce9b4bb3f38_module.so\n", + "[100%] Built target nestml_db7c0041c73544bfa402cce9b4bb3f38_module_module\n", + "[100%] Built target nestml_db7c0041c73544bfa402cce9b4bb3f38_module_module\n", + "Install the project...\n", + "-- Install configuration: \"\"\n", + "-- Installing: /tmp/nestml_target_xi9ld_gb/nestml_db7c0041c73544bfa402cce9b4bb3f38_module.so\n" + ] + } + ], "source": [ "from pynestml.codegeneration.nest_code_generator_utils import NESTCodeGeneratorUtils\n", "\n", "# generate and build code\n", "input_layer_module_name, input_layer_neuron_model_name = \\\n", - " NESTCodeGeneratorUtils.generate_code_for(\"../../../models/neurons/ignore_and_fire_neuron.nestml\")\n", + " NESTCodeGeneratorUtils.generate_code_for(\"models/neurons/ignore_and_fire_neuron.nestml\")\n", "\n", "# ignore_and_fire\n", "output_layer_module_name, output_layer_neuron_model_name, output_layer_synapse_model_name = \\\n", @@ -24,7 +1273,31 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('nestml_db7c0041c73544bfa402cce9b4bb3f38_module',\n", + " 'iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml',\n", + " 'neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml')" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# output_layer_module_name, output_layer_neuron_model_name, output_layer_synapse_model_name = ('/tmp/nestml_target_xi9ld_gb/nestml_db7c0041c73544bfa402cce9b4bb3f38_module.so',\n", + "# 'iaf_psc_exp_neuron_nestml__with_neuromodulated_stdp_synapse_nestml',\n", + "# 'neuromodulated_stdp_synapse_nestml__with_iaf_psc_exp_neuron_nestml')" + ] + }, + { + "cell_type": "code", + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -40,7 +1313,8 @@ " lmbda=1E-6,\n", " sim_time=None, # if None, computed from pre and post spike times\n", " synapse_parameters=None, # optional dictionary passed to the synapse\n", - " fname_snip=\"\"):\n", + " fname_snip=\"\",\n", + " debug=True):\n", "\n", " nest.ResetKernel()\n", " nest.Install(module_name)\n", @@ -54,7 +1328,7 @@ " \"w\": 1.,\n", " \"n\": 1.,\n", " \"d\": delay,\n", - " # \"receptor_type\": 0,\n", + " \"alpha\": 0,\n", " \"mu_minus\": 0.,\n", " \"mu_plus\": 0.\n", " })\n", @@ -72,12 +1346,14 @@ "\n", " spikedet_pre = nest.Create(\"spike_recorder\")\n", " spikedet_post = nest.Create(\"spike_recorder\")\n", - " #mm = nest.Create(\"multimeter\", params={\"record_from\" : [\"V_m\"]})\n", + " if debug:\n", + " mm = nest.Create(\"multimeter\", params={\"record_from\" : [\"V_m\"]})\n", "\n", " nest.Connect(pre_sg, pre_neuron, \"one_to_one\", syn_spec={\"delay\": 1.})\n", " nest.Connect(post_sg, post_neuron, \"one_to_one\", syn_spec={\"delay\": 1., \"weight\": 9999.})\n", " nest.Connect(pre_neuron, post_neuron, \"all_to_all\", syn_spec={\"synapse_model\": \"stdp_nestml_rec\"})\n", - " #nest.Connect(mm, post_neuron)\n", + " if debug:\n", + " nest.Connect(mm, post_neuron)\n", "\n", " nest.Connect(pre_neuron, spikedet_pre)\n", " nest.Connect(post_neuron, spikedet_post)\n", @@ -100,12 +1376,16 @@ " dt = actual_t_post_sp - actual_t_pre_sp\n", " dw = (updated_weight - initial_weight) / lmbda\n", "\n", + " if debug:\n", + " fig, ax = plt.subplots()\n", + " ax.plot(mm.events[\"times\"], mm.events[\"V_m\"])\n", + "\n", " return dt, dw" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -131,7 +1411,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -142,7 +1422,7 @@ "\n", " dt_vec = []\n", " dw_vec = []\n", - " for post_spike_time in np.arange(25, 175).astype(float):\n", + " for post_spike_time in np.linspace(25, 175, 20).astype(float):\n", " dt, dw = run_network(pre_spike_time, post_spike_time,\n", " module_name,\n", " neuron_model_name,\n", @@ -159,29 +1439,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "DEBUG:matplotlib.pyplot:Loaded backend qtagg version 5.15.10.\n" - ] - } - ], + "outputs": [], "source": [ - "%matplotlib qt\n", "dt_vec, dw_vec, delay = stdp_window(output_layer_module_name, output_layer_neuron_model_name, output_layer_synapse_model_name,\n", " synapse_parameters={\"alpha\": .5})\n", "\n", "plot_stdp_window(dt_vec, dw_vec, delay)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "cart_pole", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -195,7 +1473,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.8" + "version": "3.11.4" } }, "nbformat": 4,