diff --git a/demos/simple_tracker_inline.ipynb b/demos/simple_tracker_inline.ipynb index 10088e3..1d99670 100644 --- a/demos/simple_tracker_inline.ipynb +++ b/demos/simple_tracker_inline.ipynb @@ -4,7 +4,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Configuration" + "# SIMCad Demos: Simple Tracker" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Configuration\n", + "We begin with a simple configuration file that only defines a single exogenous state: a sinusoidal `signal`" ] }, { @@ -13,149 +21,411 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", + "# SimCAD related imports\n", "from datetime import timedelta\n", - "\n", - "from SimCAD import configs\n", "from SimCAD.configuration import Configuration\n", - "from SimCAD.configuration.utils import exo_update_per_ts, proc_trigger, ep_time_step\n", + "from SimCAD.configuration.utils import exo_update_per_ts, ep_time_step\n", "\n", - "seed = {\n", + "# System specific imports\n", + "import numpy as np\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# List of all the states in the system and their initial conditions\n", + "# In the current version of SimCAD, `timestamp` is mandatory\n", + "# The `signal` state is the exogenous state that we'll model\n", + "initial_conditions = {\n", + " 'signal': float(0),\n", + " 'timestamp': '2018-01-01 00:00:00'\n", "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", "\n", - "# Behaviors\n", - "def tracker(step, sL, s):\n", - " currentSignal = s['signal']\n", - " currentFollow = s['follow']\n", - " dif = currentSignal - currentFollow\n", - " return {'value': dif}\n", "\n", - "# Mechanisms\n", - "def add(step, sL, s, _input):\n", - " y = 'follow'\n", - " x = s['follow'] + _input['value']\n", - " return (y, x)\n", "\n", - "# Exogenous States\n", - "period = 50\n", - "def sinusoid(step, sL, s, _input):\n", - " y = 'signal'\n", - " x = s['elapsed_time'] + t_delta.seconds\n", - " x = np.sin(x * 2 * np.pi / period)\n", - " return (y, x)\n", - "\n", - "def delta_time(step, sL, s, _input):\n", - " y = 'elapsed_time'\n", - " x = s['elapsed_time'] + t_delta.seconds\n", - " return (y, x)\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Definitions of functions that update the exogenous states\n", + "# Functions must return a tuple containing the name of the state being updated and its new value\n", + "# For now, ignore all the arguments passed to the function, except `s`, \n", + "# which contains a copy of the current values of all the states\n", "\n", + "# Definition of the function that updates the `timestamp` state\n", + "# In the current version of SimCAD, `timestamp` is a mandatory state\n", "ts_format = '%Y-%m-%d %H:%M:%S'\n", - "t_delta = timedelta(days=0, minutes=0, seconds=1)\n", + "t_delta = timedelta(days=0, minutes=0, seconds=1) # In this example, a time_step is defined as 1 second. The user can change this\n", "def time_model(step, sL, s, _input):\n", " y = 'timestamp'\n", " x = ep_time_step(s, dt_str=s['timestamp'], fromat_str=ts_format, _timedelta=t_delta)\n", " return (y, x)\n", "\n", - "# Genesis States\n", - "genesis_states = {\n", - " 'signal': float(0),\n", - " 'follow': float(0),\n", - " 'elapsed_time': float(0),\n", - " 'timestamp': '2018-01-01 00:00:00'\n", - "}\n", + "# Definition of the function that updates the `signal` state\n", + "# It's a simple sine wave with amplitude 1 and period 50 time_steps\n", + "period = 50\n", + "def sinusoid(step, sL, s, _input):\n", + " y = 'signal'\n", + " x = s['time_step']\n", + " x = np.sin(x * 2 * np.pi / period)\n", + " return (y, x)\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", "\n", - "# remove `exo_update_per_ts` to update every ts\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# This maps the exogenous states to their corresponding updating functions\n", "exogenous_states = exo_update_per_ts(\n", " {\n", - " \"signal\": sinusoid,\n", - " 'elapsed_time': delta_time,\n", - " \"timestamp\": time_model\n", + " 'signal': sinusoid, # The `signal` state is updated by the `sinusoid` function defined above\n", + " 'timestamp': time_model # The `timestamp` state is updated by the `time_model` function defined above\n", " }\n", ")\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", "\n", - "env_processes = {\n", - "}\n", - "\n", - "mechanisms = {\n", - " \"add\": {\n", - " \"behaviors\": {\n", - " \"tracker\": tracker\n", - " },\n", - " \"states\": { \n", - " \"follow\": add\n", - " }\n", - " }\n", - "}\n", - "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Settings of general simulation parameters, unrelated to the system itself\n", + "# `T` is the number of discrete units of time the simulation will run for\n", + "# `N` is the number of times the simulation will be run\n", + "# In this example, we'll run the simulation once (N=1) and its duration will be of 50 discrete units of time\n", "sim_config = {\n", - " \"N\": 1,\n", - " \"T\": range(50)\n", + " 'T': range(50),\n", + " 'N': 1\n", "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", "\n", - "configs.append(\n", - " Configuration(\n", - " sim_config=sim_config,\n", - " state_dict=genesis_states,\n", - " seed=seed,\n", - " exogenous_states=exogenous_states,\n", - " env_processes=env_processes,\n", - " mechanisms=mechanisms\n", - " )\n", - ")" + "# We'll ignore these components of the configuration for now\n", + "env_processes = {}\n", + "seeds = {}\n", + "mechanisms = {}\n", + "\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# The configurations above are then packaged into a `Configuration` object\n", + "config = Configuration(sim_config=sim_config,\n", + " state_dict=initial_conditions,\n", + " seed=seeds,\n", + " exogenous_states=exogenous_states,\n", + " env_processes=env_processes,\n", + " mechanisms=mechanisms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# Run the engine" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from SimCAD.engine import ExecutionMode, ExecutionContext, Executor\n", - "# from demos import simple_tracker_config\n", - "from SimCAD import configs\n", - "exec_mode = ExecutionMode()\n", - "\n", - "single_config = [configs[0]]\n", - "single_proc_ctx = ExecutionContext(exec_mode.single_proc)\n", - "run = Executor(single_proc_ctx, single_config)\n", - "run_raw_result = run.main()[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Analyze the results" + "# Running the engine\n", + "We are now ready to run the engine with the configuration defined above. Instantiate an ExecutionMode, an ExecutionContext and an Executor objects, passing the Configuration object to the latter. Then run the `main()` method of the Executor object, which returns the results of the experiment in the first element of a tuple." ] }, { "cell_type": "code", "execution_count": 2, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "single_proc: []\n" + "single_proc: []\n" ] - }, + } + ], + "source": [ + "from SimCAD.engine import ExecutionMode, ExecutionContext, Executor\n", + "exec_mode = ExecutionMode()\n", + "exec_context = ExecutionContext(exec_mode.single_proc)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.main() # The `main()` method returns a tuple; its first elements contains the raw results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analyzing the results\n", + "We can now convert the raw results into a DataFrame for analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "scrolled": false + }, + "outputs": [ { "data": { "text/plain": [ - "" + "count 5.100000e+01\n", + "mean -3.800038e-17\n", + "std 7.071068e-01\n", + "min -9.980267e-01\n", + "25% -6.845471e-01\n", + "50% 0.000000e+00\n", + "75% 6.845471e-01\n", + "max 9.980267e-01\n", + "Name: signal, dtype: float64" ] }, - "execution_count": 2, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYYAAAEACAYAAAC3adEgAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3Xd4VGX6//H3nU6AEFLoKZTQS5BQFUFAVlGai4oVG6y6ylpXUdeKu7ZdLAjKF1R2dcWyIiAoUgKIiBB6T0JCSSgJCQSSAGnP748M/hIMJGQmOVPu13XNlTOn3hNlPnnOec55xBiDUkopdY6X1QUopZRyLhoMSimlytFgUEopVY4Gg1JKqXI0GJRSSpWjwaCUUqocDQallFLlaDAopZQqR4NBKaVUOT5WF1AdYWFhJjo62uoylFLKpWzYsOGYMSa8svVcMhiio6NJSEiwugyllHIpIrK/KuvpqSSllFLlaDAopZQqR4NBKaVUOS55jUEppS6ksLCQtLQ0zpw5Y3UplgkICKBFixb4+vpWa3uHBIOIfARcD2QYYzpXsFyAd4BhQD5wlzFmo23ZOOA526qTjTGzHVGTUsozpaWlUb9+faKjoyn96vEsxhiysrJIS0ujZcuW1dqHo04lfQJcc5Hl1wIxttcEYDqAiIQALwC9gV7ACyLS0EE1KaU80JkzZwgNDfXIUAAQEUJDQ+1qMTkkGIwxq4Dsi6wyEvi3KbUWCBaRpsAfgCXGmGxjzHFgCRcPGKWUqpSnhsI59n7+2rrG0Bw4WOZ9mm3eheYrCxzMzueXvVmkHc+vcHlQHV/6tAqlQ9MgvL08+x+eUu7MZS4+i8gESk9DERkZaXE17uFIzhl+STnGmuQsfknJIu346d+WVfQHx7nhwYMCfOjTKpR+rUPp2zqMto3refxfaEpdzH333cdjjz1Gx44dHbrfevXqkZub69B9Qu0FQzoQUeZ9C9u8dGDgefNXVLQDY8wMYAZAXFycqYkiPYExhlVJx3h7aSKbDpwAoEEdX/q0CmF8/1b0ax1Km0YVf9EfPXmGX/Zm8cveLNakHOPHnUcBaNYggAcGtuamnhH4+3jX6udRyhXMnDnT6hIuSW0Fw3zgIRGZQ+mF5hxjzGERWQz8vcwF56HApFqqyaMYY1izN4t/LUlkw/7jNA+uw9PXtueKNmF0bBqEVxVODTUOCmBU9+aM6l56tu9gdj6/pGTx5fqD/G3eDqav2MtDg2IY06MFfj56i4zyTHl5edx0002kpaVRXFzM3/72N6ZPn85bb71FXFwcs2bN4vXXXyc4OJhu3brh7+/P1KlTueuuuwgKCiIhIYEjR47wxhtvMGbMGHJzcxk5ciTHjx+nsLCQyZMnM3LkyBr9DI7qrvo5pX/5h4lIGqU9jXwBjDEfAIso7aqaTGl31btty7JF5BVgvW1XLxtjLnYRW1XD2pTSQFiXmk3TBgFMHtWZm+Ii7P7yjggJJCIkkBt7tGB18jH++WMiz8zdxrQVyUwcHMMN3Zvj460Boazz0oId7Dx00qH77NgsiBeGd7rg8h9++IFmzZqxcOFCAHJycpg+fToAhw4d4pVXXmHjxo3Ur1+fQYMG0a1bt9+2PXz4MKtXr2b37t2MGDGCMWPGEBAQwNy5cwkKCuLYsWP06dOHESNG1OjpW4cEgzHmlkqWG+DPF1j2EfCRI+pQ5R3LPctfv97K8t0ZNKrvz0sjOnFzzwgCfB17ukdE6B8TzhVtwliRmMmUJYn89eutfLBiL1NujqVbRLBDj6eUM+vSpQuPP/44Tz31FNdffz39+/f/bdm6desYMGAAISEhANx4440kJib+tnzUqFF4eXnRsWNHjh4tPVVrjOGZZ55h1apVeHl5kZ6eztGjR2nSpEmNfQaXufisLs3alCwmfr6JnNOFPDOsPXf2jXZ4IJxPRLiqXSMGtg1nyc6jvLRgJ2M+WMMzwzpwVz/PvNlIWetif9nXlLZt27Jx40YWLVrEc889x+DBg6u8rb+//2/Txtbb47PPPiMzM5MNGzbg6+tLdHR0jd/Vre18N1NSYng/Pplb/28t9fx9+PbPlzPhytY1HgpliQhDOzVh4cQrGNA2nJcW7OSBTzeSc7qw1mpQyiqHDh0iMDCQ22+/nSeffJKNGzf+tqxnz56sXLmS48ePU1RUxP/+979K95eTk0OjRo3w9fUlPj6e/fur9ORsu2iLwY1k5Z7l0S+3sCoxk+HdmvGPG7pQz9+6/8TBgX78351xzPwpldd/2M3w91bz/q2X0aVFA8tqUqqmbdu2jSeffBIvLy98fX2ZPn06TzzxBADNmzfnmWeeoVevXoSEhNC+fXsaNLj4v4fbbruN4cOH06VLF+Li4mjfvn2NfwY511xxJXFxcUYH6ilv/b5sHv7vJrLzC3hxeCdu6RXhVKduNuw/zsP/3cix3AKeva4Dd/aNcqr6lPvYtWsXHTp0sLqMC8rNzaVevXoUFRUxevRo7rnnHkaPHu3w41T0exCRDcaYuMq21VNJbmDpzqPc+n9rCfD1Yu6D/bi1d6TTfen2iGrIwon9uSImjBfm7+C1H3bjin+UKGWvF198kdjYWDp37kzLli0ZNWqU1SX9jp5KcnE/bD/Cw59vpGPTIP59T28aBFbvMbu1oWFdP2beGcfz87fz4coUiosNz17XwelCTKma9NZbb1ldQqU0GFzYom2Hmfj5Jrq0aMDse3oRFOC8oXCOl5fwysjO+Hh5MXN1KkUlhheGd9RwUA5ljPHo/6fsbY1rMLioBVsO8cgXm4mNCOaTu3tS3wVC4RwR4YXhHfES4aOfUykuMbw0olOV7r5WqjIBAQFkZWV57KO3z43HEBAQUO19aDC4oHmb03n0i83ERYXw0d09Le15VF0iwt+u74Cvt/DhqhSKSgyvjuqs4aDs1qJFC9LS0sjMzLS6FMucG8GtulzvG8XDfbMxjSe+2kKvliF8dFdPAv1c9z+hiPD0te3x9hKmrdhLcUkJr93QVcNB2cXX17faI5epUq77reKB4vdk8MRXW+jbOpSZd/akjp/rP8lURHjyD+3w8RLeXZ5MSF1/nr625vtpK6UuTIPBRSRnnGLifzfRrkkQM+6Ic4tQOEdEePTqtmTlFfDByr3ENKrHH3tUvxmslLKP3sfgAo7nFXDv7AT8fb2ZOS6Oui54TaEyIsKLIzrRr3Uok77Zxob9+pBdpayiweDkCopKuP/TDRw+cYYP7+hB8+A6VpdUY3y9vZh222U0Cw7gT//ZcMEhRpVSNUuDwYkZY3hh/nZ+Tc3m9TFd6BHVsPKNXFxwoB8zx/XkbFEJ981OIO9skdUlKeVxNBic2Mc/7+PzdQd5YGBrRnf3nHPubRrV4/1bLyPx6Cke+WIzJSX66AylapNDgkFErhGRPSKSLCJPV7B8iohstr0SReREmWXFZZbNd0Q97mDFngwmL9zJ0I6NeXJoO6vLqXVXtg3nb9d3ZMnOo7z54x6ry1HKo9h9FVNEvIH3gauBNGC9iMw3xuw8t44x5tEy6z8MdC+zi9PGmFh763AnB7LyedjWA2nKzbEe26//rn7RJGXkMn3FXjo1C+L6rs2sLkkpj+CIFkMvINkYk2KMKQDmABcbqfoW4HMHHNctFRaX8JcvNoHAjDt6uGUPpKoSEV4a0YnukcFM+mabXoxWqpY4IhiaAwfLvE+zzfsdEYkCWgLLy8wOEJEEEVkrIs73/Nla9t6yJDYdOMGro7sQERJodTmW8/X24p2bu2MMPPbFFor1eoNSNa62Lz6PBb42xhSXmRdlGzjiVuBtEWld0YYiMsEWIAnu+gyUdanZTI1P5obLmjOim542OScyNJCXR3Zi3b5spsUnW12OUm7PEcGQDkSUed/CNq8iYznvNJIxJt32MwVYQfnrD2XXm2GMiTPGxIWHh9tbs9PJOV3Io19spkXDQF4e2dnqcpzO6O6lYfn2siQ2HjhudTlKuTVHBMN6IEZEWoqIH6Vf/r/rXSQi7YGGwC9l5jUUEX/bdBhwObDz/G3dnTGG577dzpGTZ3hnbKxLPi21pokIk0d3pklQAI/M2cypM4VWl6SU27I7GIwxRcBDwGJgF/ClMWaHiLwsIiPKrDoWmGPKjyDRAUgQkS1APPBa2d5MnuKbjeks2HKIR4fE0D3S/W9iq66gAF/eGRtL2vF8Xpi/w+pylHJb4orj7sbFxZmEhASry3CI/Vl5DHvnJzo1b8Dn4/vg7aFdUy/Fv5Yk8u6yJN4ZG8vI2Ar7OSilKiAiG2zXdC9K73y2UFFxCX+ZsxlvL2HKzbEaClU0cVAbLosM5rm52zmYrV1YlXI0DQYLzVydyuaDpV1T3fnheI7m4+3FO2O7U2IMz8zdZvf4tkqp8jQYLLI/K4+3lyYytGNjhmvX1EsWERLIX69pz09Jx/h284U6wSmlqkODwQLGGJ6dux0fLy/tmmqH2/tE0T0ymFe+20V2XoHV5SjlNjQYLDB3Uzqrk4/x1DXtaNIgwOpyXJa3l/CPG7pw8nQhkxd6XGc2pWqMBkMty8o9yyvf7aRHVENu6x1ldTkur32TIO4f0JpvNqbzU5J73hGvVG3TYKhlkxfuIvdsEf+4oYvHPjXV0R4a1IaWYXV5du52ThcUV76BUuqiNBhq0arETOZuSueBAa1p27i+1eW4jQBfb/4+ugsHsvN5e1mi1eUo5fI0GGpJfkERz367jVbhdXnwqjZWl+N2+rYO5ea4CGb+lMr29Byry1HKpWkw1JJ3liZxMPs0fx/dhQBfb6vLcUvPDOtAw0A/Jn2zTR/PrZQdNBhqwc5DJ5m5OpWxPSPo0yrU6nLcVoNAX14Y3pFt6Tl8smaf1eUo5bI0GGqYMYYXF+wgKMCHSdd2sLoct3d916Zc2Tact5cmciz3rNXlKOWSNBhq2KJtR1iXms0Tf2hHg0Bfq8txeyLC89d35HRBMf/8US9EK1UdGgw16HRBMX9ftIsOTYMY2zPS6nI8RptG9RjXL5o56w/ohWilqkGDoQbNWJVC+onTvDC8oz45tZZNHBxDw0A/Xl6wUx+yp9Ql0mCoIeknTjN9ZTLXdWmqF5wt0KCOL08Mbce6fdl8t/Ww1eUo5VIcEgwico2I7BGRZBF5uoLld4lIpohstr3uK7NsnIgk2V7jHFGPM3jt+90YA5OGtbe6FI91c88IOjYN4h+Ldukd0UpdAruDQUS8gfeBa4GOwC0i0rGCVb8wxsTaXjNt24YALwC9gV7ACyLi8mNbrkvNZsGWQ/xpQGtaNAy0uhyP5e0lvDiiE4dyzvDByr1Wl6OUy3BEi6EXkGyMSTHGFABzgJFV3PYPwBJjTLYx5jiwBLjGATVZprjE8NKCHTRtEMADA1pbXY7H69UyhOu7NuWDlXtJP3Ha6nKUcgmOCIbmwMEy79Ns8873RxHZKiJfi0jEJW7rMr5KOMiOQyeZNKwDdfz0DmdnMGlY6f0j/1i0y+JKlHINtXXxeQEQbYzpSmmrYPal7kBEJohIgogkZGY65+OVc04X8ubiPfSMbsjwrk2tLkfZNA+uw/0DWvPd1sP8mpJldTlKOT1HBEM6EFHmfQvbvN8YY7KMMeduQ50J9KjqtmX2McMYE2eMiQsPD3dA2Y43fcVesvMLeGF4J0S0e6ozuX9Aa5o1CGDywl2U6HOUlLooRwTDeiBGRFqKiB8wFphfdgURKfvn8wjgXJt+MTBURBraLjoPtc1zOYdOnObjn1MZHduczs0bWF2OOk8dP28eH9qObek5LNym3VeVuhi7g8EYUwQ8ROkX+i7gS2PMDhF5WURG2FabKCI7RGQLMBG4y7ZtNvAKpeGyHnjZNs/lTFmSiDHw6NVtrS5FXcCo7s1p36Q+b/24h4KiEqvLUcppiSveFRoXF2cSEhKsLuM3e46c4tp3VnHP5S157vqKeuoqZxG/J4O7P17PSyM6Ma5ftNXlKFWrRGSDMSausvX0zmcHeOOH3dT19+HPOgCP0xvYNpw+rUJ4d1kSuWeLrC5HKaekwWCnX1OyWLY7gwcGtqZhXT+ry1GVEBEmXduBrLwCZqxKsbocpZySBoMdjDG89sNumgQFcHe/llaXo6qoW0Qw13VpysyfUsg4dcbqcpRyOhoMdli84wibDpzg0atj9GY2F/PEH9pRUFTCe8uSrS5FKaejwVBNhcUlvPHDHto0qscfL2thdTnqErUMq8stvSL5fN0BUo/lWV2OUk5Fg6Gavkw4SMqxPJ66pj0+3vprdEUTB8fg5+PFW4v3WF2KUk5Fv9GqIb+giLeXJhEX1ZAhHRpZXY6qpvD6/ozv34qF2w6z+eAJq8tRymloMFTDxz/vI/PUWSYNa6+PvnBx469sRVg9P17/frfVpSjlNDQYLlHO6UI+XLmXIR0a0SMqxOpylJ3q2e4/+SUlizXJx6wuRymnoMFwiWb9lMLJM0X66As3ckuvSJo2COCfSxJ1fGil0GC4JNl5BcxancqwLk3o1EwflOcuAny9eWhQGzbsP86KROd8pLtStUmD4RJ8uHIv+YXFPDpEWwvu5sYeEUSE1OFfP2qrQSkNhirKOHWG2b/sY1Rsc2Ia17e6HOVgfj5e/GVwW7al5/DjzqNWl6OUpTQYqmha/F4Kiw1/GRxjdSmqhoyKbUar8Lr868dEHcxHeTQNhio4dOI0//31AGMua0F0WF2ry1E1xMfbi0eGtGXP0VN8p4P5KA+mwVAF7y1PxmB4eLA+VtvdXd+lKe0a1+ftJYkUFetgPsozOSQYROQaEdkjIski8nQFyx8TkZ0islVElolIVJllxSKy2faaf/62VjuQlc9XCQe5pVckLRoGWl2OqmFeXsJjQ9uSciyPbzcfsrocpSxhdzCIiDfwPnAt0BG4RUTOH8ZsExBnjOkKfA28UWbZaWNMrO01AifzzrIkvL1EB+HxIEM7NqZL8wa8syxRhwBVHskRLYZeQLIxJsUYUwDMAUaWXcEYE2+Mybe9XQu4xONIkzNymbspjTv7RtE4KMDqclQtEREeH9qWg9mn+WrDQavLUarWOSIYmgNl//Wk2eZdyL3A92XeB4hIgoisFZFRF9pIRCbY1kvIzKydm5DeXZZEgK839w9oXSvHU85jQNtwekQ1ZOryZM4WFVtdjlK1qlYvPovI7UAc8GaZ2VG2walvBd4WkQq/hY0xM4wxccaYuPDw8BqvNTnjFAu2HuLOvtGE1vOv8eMp5yIiPDqkLYdzzvBlQprV5ShVqxwRDOlARJn3LWzzyhGRIcCzwAhjzNlz840x6bafKcAKoLsDarLbe8uTCfDxZnx/HbLTU13eJpQeUQ2ZHq+tBuVZHBEM64EYEWkpIn7AWKBc7yIR6Q58SGkoZJSZ31BE/G3TYcDlwE4H1GSX5Ixc5m85xJ39orS14MFEhEeGxHAo5wxfaatBeRC7g8EYUwQ8BCwGdgFfGmN2iMjLInKul9GbQD3gq/O6pXYAEkRkCxAPvGaMsTwYpi5PIsDHmwn9W1ldirLYFW3CuCwymGnxydpDSXkMH0fsxBizCFh03rzny0wPucB2a4AujqjBUfZmlrYWxvdvpa0FZWs1tOXOj9bx1YaD3NY7qvKNlHJxeufzeaYuT8bfx5vxV2prQZXqHxNG98hgpsXv1VaD8ggaDGWkZOYyb3M6d/SNIkxbC8rmXKsh/cRpvt6g1xqU+9NgKGPq8mT8fLwYr9cW1HmujAkjNiKY9/Vag/IAGgw2KZm5fLs5nTv6RBFeX1sLqrxzPZTST5zmfxu11aDcmwaDzbnWwoQr9S5nVbEBbcPpFhHM1OXaalDuTYMBSD2Wx7eb07m9t7YW1IWVbTV8o60G5cY0GChtLfh6ezFhgF5bUBc38FyrIT6ZQh2vQbkpjw+GA1n5fLs5ndt6R9Govj5BVV2ciPCXwW1IO36auZt+9+QXpdyCxwfDtBXJeHsJf9LWgqqiq9o1onPzIKbFJ+sob8oteXQwpB3P5+sNaYztGaHjLagqExEeHhTDvqx8FmzVUd6U+/HoYJi+Yi8i6HgL6pJd3aEx7ZvU573lyRSXGKvLUcqhPDYYDuec5quENMb0iKBZcB2ry1EuxsurtNWQkpnHom2HrS5HKYfy2GD4cGUKJcbw4EBtLajqubZzE2Ia1eO95UmUaKtBuRGPDIaMk2f4fN0BbrisOREhgVaXo1yUl5fw0KA2JB7N5cedR6wuRymH8chgmLEqhcLiEh4c2MbqUpSLu75rM1qF1eWdZckYo60G5R4cEgwico2I7BGRZBF5uoLl/iLyhW35ryISXWbZJNv8PSLyB0fUczHHcs/y2a8HGBXbnOiwujV9OOXmvL2EB69qw67DJ1m6K6PyDZRyAXYHg4h4A+8D1wIdgVtEpON5q90LHDfGtAGmAK/btu1I6VCgnYBrgGm2/dWYmT+lcqaomAev0taCcoyRsc2IDAnkveVJ2mpQbsERLYZeQLIxJsUYUwDMAUaet85IYLZt+mtgsIiIbf4cY8xZY0wqkGzbX404nlfAf37Zx/Vdm9GmUb2aOozyML7eXjw4sDVb03JYkZhpdTlK2c0RwdAcOFjmfZptXoXr2MaIzgFCq7itw3z0cyp5BcU8PEhbC8qxbrisBc2D6/DuMm01qJqRnJHL3R+v40BWfo0fy2UuPovIBBFJEJGEzMzq/VWWnVfAdV2b0rZxfQdXpzydn48XDwxszaYDJ/g5OcvqcpQbej8+mbUp2dT1r9Gz7YBjgiEdiCjzvoVtXoXriIgP0ADIquK2ABhjZhhj4owxceHh4dUq9NXRXXh3bPdqbatUZW6Ma0GToADeXZ5kdSnKzaQey2Pe5nRu7xNJaC0MO+yIYFgPxIhISxHxo/Ri8vzz1pkPjLNNjwGWm9L29nxgrK3XUksgBljngJouyNtLanL3yoP5+3hz/4BWrEvNZm2KthqU40yLLx0aYPyVtfOwT7uDwXbN4CFgMbAL+NIYs0NEXhaREbbVZgGhIpIMPAY8bdt2B/AlsBP4AfizMabY3pqUssrYXpGE1fPn3WXaalCOcTA7n282pXNr78haGxrAxxE7McYsAhadN+/5MtNngBsvsO2rwKuOqEMpqwX4lrYaJi/cRcK+bOKiQ6wuSbm4aSv24i3Cn2px2GGXufislKu4tXckIXX9eHd5stWlKBeXfuI0X284yM09I2jSoPaGBtBgUMrBAv18GN+/FasSM9l88ITV5SgX9uHKvQDcX8sP+9RgUKoG3NE3iuBAX97Taw2qmo6ePMOc9QcZ06P0HpnapMGgVA2o5+/DvZe3ZNnuDLan51hdjnJBH65MobjE8MCA2r8hV4NBqRoy7vJo6gf48J7e16AuUeaps3z2635Gd29OZGjtDw2gwaBUDQkK8OXuy1uyeMdRdh85aXU5yoXM/Kl0aIA/W/SwTw0GpWrQPZdHU8/fh/e0h5Kqouy8Av6zdj8jujWjpUVDA2gwKFWDggP9GNcvikXbDpN09JTV5SgXMPOnFE4XFvOQhQ/71GBQqobde0Ur6vh6630NqlLH8wqYvWYf13VpSptG1j3sU4NBqRoWUtePcf2i+W7rIZIztNWgLmzm6hTyC4uZODjG0jo0GJSqBeP721oNy7TVoCp2PK+AT34ubS1YPTSABoNStSCkrh939o1mwdZDJGfkWl2OckKzVqc6RWsBNBiUqjXj+7ekjq+33tegfud4XgGfrNnHMCdoLYAGg1K1JrSeP3f0jWL+Fm01qPJmrU4l92wREwdZ31oADQalatWE/q0I8PFmqrYalM2J/NLWwnVdmtKuifWtBdBgUKpWhdbz505bq2FvprYa1P9vLTw82Lr7Fs5nVzCISIiILBGRJNvPhhWsEysiv4jIDhHZKiI3l1n2iYikishm2yvWnnqUcgXjr2yFv483U/W+Bo93Ir+0J9KwLk1o3yTI6nJ+Y2+L4WlgmTEmBlhme3++fOBOY0wn4BrgbREJLrP8SWNMrO212c56lHJ6YbZrDfM2p2urwcN9tDqVU2eLnKInUln2BsNIYLZtejYw6vwVjDGJxpgk2/QhIAMIt/O4Srm0CVe2ws/HS1sNHiwnv5CPf97HtZ2dq7UA9gdDY2PMYdv0EaDxxVYWkV6AH7C3zOxXbaeYpoiIv531KOUSwur5c2ffaG01eLBZq1OcsrUAVQgGEVkqItsreI0su54xxgDmIvtpCvwHuNsYU2KbPQloD/QEQoCnLrL9BBFJEJGEzMzMyj+ZUk5uwpWtCPD15p2l2kPJ02TnFfCRrbXQoalztRagCsFgjBlijOlcwWsecNT2hX/uiz+jon2ISBCwEHjWGLO2zL4Pm1JngY+BXhepY4YxJs4YExcermeilOsLq+fPXf1K74bW8Ro8y4er9pJXUMRjV7e1upQK2XsqaT4wzjY9Dph3/goi4gfMBf5tjPn6vGXnQkUovT6x3c56lHIpE65sRT0/H6YsSbS6FFVLMk6dYfaafYyKbU6ME9zlXBF7g+E14GoRSQKG2N4jInEiMtO2zk3AlcBdFXRL/UxEtgHbgDBgsp31KOVSggP9uLd/6Shv29J0bGhPMC1+L4XFhr844bWFc6T00oBriYuLMwkJCVaXoZRDnDxTyJVvxNM9IpiP777g2VTlBg6dOM3AN1cwuntzXh/TtdaPLyIbjDFxla2ndz4rZbGgAF/+dGVr4vdksmH/cavLUTVoanwyBuNUdzlXRINBKScwrl8UYfX8+NeSPVaXomrIgax8vlx/kFt6RdKiYaDV5VyUBoNSTiDQz4cHBrbh5+Qs1uw9ZnU5qga8sywJby/hz1c5d2sBNBiUchq39Y6kSVAA//oxEVe89qcubG9mLnM3pXFHnygaBwVYXU6lNBiUchIBvt48NKgNCfuPsypJWw3u5O2lSQT4enP/wNZWl1IlGgxKOZGb4iJo0bAO//xxj7Ya3MSuwydZsOUQd18eTVg913jqjwaDUk7Ez8eLiYNj2JqWw+IdR6wuRznAP39MpL6/D+P7t7K6lCrTYFDKydzQvTltGtXjjcV7KCouqXwD5bTW78tm6a6j3D+wNcGBflaXU2UaDEo5GR9vL566pj0pmXl8mZBmdTmqmowx/GPRLhrV9+eey1taXc6uyxzVAAARRElEQVQl0WBQygkN6dCIuKiGTFmaSH5BkdXlqGpYvOMoGw+c4NGr21LHz9vqci6JBoNSTkhEmDSsPZmnzvLR6lSry1GXqKi4hDcW76Z1eF1u7NHC6nIumQaDUk6qR1QIQzs25oOVKWTlnrW6HHUJvkxIIyUzj79e0x4fb9f7mnW9ipXyIH+9ph35BUVMjdchQF1FfkERby9NpEdUQ4Z2vOiglk5Lg0EpJ9amUX1u7hnBp2v3cyAr3+pyVBV8tDqVjFNnmXRte0qHmnE9GgxKOblHhrTF20v4pz5gz+ll5xXwwcoUru7YmLjoEKvLqTYNBqWcXOOgAO69oiXzNh9ie7oO5uPM3lueRH5BEX/9QzurS7GLXcEgIiEiskREkmw/G15gveIyo7fNLzO/pYj8KiLJIvKFbRhQpdR5/jSgNcGBvrz+w26rS1EXcDA7n0/X7uemuAinHbKzquxtMTwNLDPGxADLbO8rctoYE2t7jSgz/3VgijGmDXAcuNfOepRyS0EBvjx0VRt+SjrGysRMq8tRFXhz8R68vYRHhrS1uhS72RsMI4HZtunZwKiqbiilV2UGAV9XZ3ulPM0dfaOICg3kle92UqiPynAqCfuymb/lEOP7t6JJA+d/rHZl7A2GxsaYw7bpI8CF+mYFiEiCiKwVkXNf/qHACWPMuds604DmdtajlNvy9/Hmues6kpyRy6dr91tdjrIpKTG8uGAHTYICeMBFHqtdGZ/KVhCRpUCTChY9W/aNMcaIyIWeExxljEkXkVbAchHZBlzSVTQRmQBMAIiMjLyUTZVyG0M6NKJ/TBhTliQyolszQl3kMc7u7KsNB9mefpJ3xsYS6FfpV6pLqLTFYIwZYozpXMFrHnBURJoC2H5mXGAf6bafKcAKoDuQBQSLyLnfZAsg/SJ1zDDGxBlj4sLDwy/hIyrlPkSE56/vSF5BMf9akmh1OR7v5JlC3ly8hx5RDRnRrZnV5TiMvaeS5gPjbNPjgHnnryAiDUXE3zYdBlwO7DSlo5DEA2Mutr1SqryYxvW5o08Un687wM5DJ60ux6NNXZ5MVl4BLw7v5LI3s1XE3mB4DbhaRJKAIbb3iEiciMy0rdMBSBCRLZQGwWvGmJ22ZU8Bj4lIMqXXHGbZWY9SHuHRIW1pUMeXlxbs0JHeLJKSmcvHP6dyY48WdGnRwOpyHMquE2LGmCxgcAXzE4D7bNNrgC4X2D4F6GVPDUp5ogaBvjw+tB3Pfbud77cfYViXplaX5HEmL9yFv483T7j4zWwV0TuflXJRt/SKpH2T+ry6cBdnCoutLsejxO/JYPnuDCYObkOj+q7fPfV8GgxKuShvL+GF4Z1IP3GaGatSrC7HYxQUlfDKdztpGVaXu/q51shsVaXBoJQL69s6lGFdmjBtRTKHTpy2uhyP8O9f9pGSmcdz13XAz8c9v0Ld81Mp5UGeGdYBgBfn77C4Evd36MRppixJZEDbcAa1b2R1OTVGg0EpF9eiYSCPDGnLjzuP8sP2I1aX47aMMTw/bzvFxvDKyM5u1T31fBoMSrmBe69oSYemQTw/bzsnzxRaXY5b+n77EZbuyuDRIW2JDA20upwapcGglBvw9fbitRu6cCz3LK9/r4/mdrSc04W8MH8HnZoFce8V7nnBuSwNBqXcRLeIYO7q15LPfj3A+n3ZVpfjVl77fjdZuWd57Yau+Hi7/9em+39CpTzI40Pb0jy4DpO+2cbZIr23wRHWpWbz+boD3HN5S7e7w/lCNBiUciN1/X2YPKozyRm5TF+x1+pyXN7ZomImfbOVFg3r8NhQ1x+Ap6o0GJRyM1e1b8Twbs2YFr+X5IxTVpfj0qbF72VvZh6TR3V2m0dqV4UGg1Ju6PnrO1LHz5tJ32yjpEQfslcdSUdPMW1FMiNjmzGwnfves1ARDQal3FB4fX+eHdaB9fuO89mvOtrbpSoqLuGp/22lrr8Pf7u+o9Xl1DoNBqXc1I1xLegfE8ari3bpKaVL9H78XjYeOMFLIzoR5oGj5GkwKOWmRIR/3tiNQD8fHv58s/ZSqqIN+4/z7vIkRsU2Y2SsZw5Dr8GglBtrFBTA63/syq7DJ3nzhz1Wl+P0Tp0p5JEvNtG0QQAvj+psdTmWsSsYRCRERJaISJLtZ8MK1rlKRDaXeZ0RkVG2ZZ+ISGqZZbH21KOU+r2rOzbm9j6RzFydyqrETKvLcWrPz9vBoRNneGdsLEEBvlaXYxl7WwxPA8uMMTHAMtv7cowx8caYWGNMLDAIyAd+LLPKk+eWG2M221mPUqoCzw7rSEyjejz+1Raycs9aXY5Tmrc5nbmb0nl4UBt6RIVYXY6l7A2GkcBs2/RsYFQl648BvjfG5Nt5XKXUJajj5827t3QnJ7+Qp/63VceJPs/B7Hyem7uduKiGPHRVG6vLsZy9wdDYGHPYNn0EaFzJ+mOBz8+b96qIbBWRKSJywcv/IjJBRBJEJCEzU5vDSl2qDk2DeOra9izdlcGnvx6wuhynUVRcwiNflJ6smHJzrEc8C6kylf4GRGSpiGyv4DWy7Hqm9E+QC/4ZIiJNgS7A4jKzJwHtgZ5ACPDUhbY3xswwxsQZY+LCw8MrK1spVYG7+0VzZdtwJn+3k6Sj2oUVYGp8Mhv2H2fy6M5EhLj347SrqtJgMMYMMcZ0ruA1Dzhq+8I/98WfcZFd3QTMNcb89rB4Y8xhU+os8DHQy76Po5S6GC8v4a0bu1LP34c/fbqBnNOePXZD/O4M3l2WxOjuzT22a2pF7G0zzQfG2abHAfMusu4tnHcaqUyoCKXXJ7bbWY9SqhKN6gcw/fYeHMzO56H/bqSouMTqkiyRePQUD3++iQ5Ng3h1tOd2Ta2IvcHwGnC1iCQBQ2zvEZE4EZl5biURiQYigJXnbf+ZiGwDtgFhwGQ761FKVUGvliG8OqoLPyUd45XvdlpdTq3Lzivg3tnrqePnzcxxcR71gLyqsOu3YYzJAgZXMD8BuK/M+33A79ppxphB9hxfKVV9N/WMIPHoKWauTiWmcX1u7xNldUm1oqCohPs/3cDRk2f5YkIfmjaoY3VJTkcvvyvlwSYN68BV7cJ5Yf4O1iQfs7qcGmeM4W/fbmddajZvjulK98jf3ZOr0GBQyqN5ewnv3tKd1uF1eeCzjaQey7O6pBo1a3UqXyQc5OFBbfRi80VoMCjl4eoH+DLzzp54Cdw7e73b9lSK353B3xft4trOTXh0iOeMxlYdGgxKKSJDA/nA1lNp/L8TyDtbZHVJDrVh//HfeiD986ZueHmJ1SU5NQ0GpRQAvVuF8q+bYtmw/zh3fbyOXDcJh/X7srlz1q+E1/dn1rie2gOpCjQYlFK/Gd6tGe+O7c7GAye4c9avnDrj2qeV1qZkMe6jdTRuEMCcCX1o0iDA6pJcggaDUqqc67o25f1bu7M1LYc7Zq1z2WsOa5KPcdfH62gWXIc5E/rQOEhDoao0GJRSv3NN56ZMu+0ydhzK4Y5Zv5KT71rhsCoxk7s/WU9USF3mTOhDo/oaCpdCg0EpVaGhnZrwwe092H34FLfOXMvxvAKrS6qSFXsyuO/fCbQMq8t/x/f2yDGb7aXBoJS6oMEdGvPhnT1Iysjljx+sYc8R530iqzGG//yyjwn/3kCb8Hp8Pr4PoRoK1aLBoJS6qKvaNeLf9/Ti5OkiRr6/mi8TDjrdQD+nzhTy0Oeb+Nu8HVzeJpT/ju9Nw7p+VpflsjQYlFKV6tMqlEV/uYLLIhvy16+38vhXW8gvcI7urNvTcxj+3mp+2H6Ep65pz6xxPQkO1FCwhwaDUqpKGtUP4D/39uaRITHM3ZTOiKk/k2jhYD/GGD5du58bpq/hTGEJcyb04YGBrfXmNQfQYFBKVZm3l/DIkLZ8em9vTuQXMmLqaj5du7/Wx3TIOHWGiXM289y32+nbKpSFE6+gZ3RIrdbgzsTZzhVWRVxcnElISLC6DKU8WsapMzwyZzNr9mbRMqwufxkcw/BuzfCuwb/Yj+We5cOVe/nP2v0UFhseu7otDwzQVkJVicgGY0xcZevZ1WIQkRtFZIeIlIjIBQ8mIteIyB4RSRaRp8vMbykiv9rmfyEiemJQKRfRqH4An93Xmxl39MDfx4tHvtjM0CkrWbDlECUljv2DMzuvgNe+303/1+OZtTqVYV2asuyxAfz5qjYaCjXArhaDiHQASoAPgSdsA/Scv443kAhcDaQB64FbjDE7ReRL4BtjzBwR+QDYYoyZXtlxtcWglHMpKTH8sOMIU5YkkpSRS7vG9fnTgFZc2Ta82vcRlJQYEjNO8d2Ww3z8cyr5hcWM6NaMiYNjaB1ez8GfwDNUtcVg7whuu2wHu9hqvYBkY0yKbd05wEgR2QUMAm61rTcbeBGoNBiUUs7Fy0sY1qUpf+jUhIXbDvP20kQe+3ILAO0a16dv61D6tg6lT8tQGgT6VrgPYwwpx/L4ZW9W6Ssli2zbTXXXdW3KI4NjiGlcv9Y+kyerjccMNgcOlnmfBvQGQoETxpiiMvN15AylXJi3lzCiWzOu69KUrWkn+CWl9Et+zvoDfLJmHyIQHVoXnwpO/5w4XUjmqbMANG0QwMC24fRtHUq/NmE0D9bhN2tTpcEgIkuBJhUsetYYM8/xJV2wjgnABIDIyMjaOqxSqhq8vYTukQ3pHtmQBwe24WxRMVsO5vDL3iwSj57C8PtT2AG+3sRFhdC3dSjRoYGVnYlQNajSYDDGDLHzGOlARJn3LWzzsoBgEfGxtRrOzb9QHTOAGVB6jcHOmpRStcjfx5teLUPo1VK7lLqC2riPYT0QY+uB5AeMBeab0qve8cAY23rjgFprgSillKqYvd1VR4tIGtAXWCgii23zm4nIIgBba+AhYDGwC/jSGLPDtoungMdEJJnSaw6z7KlHKaWU/fQGN6WU8hC1coObUkop96PBoJRSqhwNBqWUUuVoMCillCpHg0EppVQ5LtkrSUQygf3V3DwMOObAclyBfmbPoJ/Z/dn7eaOMMeGVreSSwWAPEUmoSnctd6Kf2TPoZ3Z/tfV59VSSUkqpcjQYlFJKleOJwTDD6gIsoJ/ZM+hndn+18nk97hqDUkqpi/PEFoNSSqmL0GBQSilVjgaDUkqpcjQYlFJKlaPBoJRSqhwNBuURRCRYRB60TTcTka9r8FixIjKspvavVE3TYFCeIhh4EMAYc8gYM6aS9e0RC2gwKJel9zEojyAic4CRwB4gCehgjOksIncBo4C6QAzwFuAH3AGcBYYZY7JFpDXwPhAO5APjjTG7ReRG4AWgGMgBhgDJQB0gHfgHkAq8AwQAp4G7jTF7LuHYK4AtwADAB7jHGLOuZn5TSgHGGH3py+1fQDSwvYLpuyj9Iq9P6Zd+DnC/bdkU4BHb9DIgxjbdG1hum94GNLdNB5fZ59Qyxw4CfGzTQ4D/XeKxVwD/Z5u+8lzt+tJXTb18HBUwSrmweGPMKeCUiOQAC2zztwFdRaQe0A/4SkTObeNv+/kz8ImIfAl8c4H9NwBmi0gMYADfqh67zHqfAxhjVolIkIgEG2NOVPPzKnVRGgxKlZ62OaekzPsSSv+NeAEnjDGx529ojLlfRHoD1wEbRKRHBft/hdIAGC0i0ZS2AKp67N8Odf6hL/J5lLKLXnxWnuIUpadsLpkx5iSQaruegJTqZptubYz51RjzPJAJRFRwrAaUXm+A0tNH1XGz7XhXADnGmJxq7kepSmkwKI9gjMkCfhaR7cCb1djFbcC9IrIF2EHphWyAN0Vkm22/ayi9SBwPdBSRzSJyM/AG8A8R2UT1W+lnbNt/ANxbzX0oVSXaK0kpJ2frlfSEMSbB6lqUZ9AWg1JKqXK0xaCUUqocbTEopZQqR4NBKaVUORoMSimlytFgUEopVY4Gg1JKqXI0GJRSSpXz/wAXBIhX2wrdFAAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "import pandas as pd\n", + "from tabulate import tabulate\n", + "df = pd.DataFrame(raw_result)\n", + "df.plot('timestamp', 'signal')\n", + "df['signal'].describe()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Modelling Internal States, Mechanisms and User Behavior\n", + "Let's now suppose we want to design a system with which an agent will interact with the intent of replicating the value of the previously defined `signal` in an internal state. The agent can read the current value of the `signal` and the current value of the internal state. And they can add or subtract any amount from the internal state." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we redefine the `initial_conditions` object in order to add the internal state, which will call `follow`" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# List of all the states in the system and their initial conditions\n", + "# In the current version of SimCAD, `timestamp` is mandatory\n", + "# The `signal` state is the exogenous state that we'll model\n", + "initial_conditions = {\n", + " 'follow': float(0),\n", + " 'signal': float(0),\n", + " 'timestamp': '2018-01-01 00:00:00'\n", + "}\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, define the function that updates the `follow` state. As defined above, all it does is add or subtract an amount from the state." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Definitions of functions that update internal states\n", + "# These functions must return a tuple containing the name of the state being updated and its new value\n", + "# As with the exogenous state update functions, the `s` argument contains a copy of the current values of all the states\n", + "# The argument `_input` contains a dictionary of inputs passed to the mechanisms by agents interacting with it \n", + "\n", + "# Definition of the function that updates the `follow` state\n", + "def add(step, sL, s, _input):\n", + " y = 'follow'\n", + " x = s['follow'] + _input['value'] # All the state update function does is add to the `follow` state the `value` passed to it\n", + " return (y, x)\n", + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The policies of the agents that interact with the system through `mechanisms` are modelled as `BEHAVIORS`. In this example, we are modelling a simple behavior in which the agent reads the current state of the exogenous `signal` and of the internal state `follow` and compares them. The `return value` of the behavior function will be passed by the SimCAD engine as the `_input` argument of the mechanism" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # \n", + "# Definitions of the Behavioral Models (or Behaviors for short) - functions that convey some information to mechanisms\n", + "# Behaviors must return a dictionary containing whatever information they should pass to the mechanism they relate to\n", + "# As with the state update functions, the `s` argument contains a copy of the current values of all the states\n", + "\n", + "# Definition of the `tracker` behavior\n", + "def tracker(step, sL, s):\n", + " currentSignal = s['signal'] # Read the current state of the exogenous `signal`\n", + " currentFollow = s['follow'] # Read the current state of the internal state `follow`\n", + " diff = currentSignal - currentFollow # Compare the two\n", + " return {'value': diff} # Return the difference between them" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we map mechanisms to states and behaviors. In our example, we define that a mechanism called `simple_mechanism` updates the `follow` state through the `add` function, driven by the `tracker` behavior." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "mechanisms = {\n", + " 'simple_mechanism': { # The name of the mechanism; can be anything\n", + " 'behaviors': { # Dictionary of behavioral models related to this mechanism\n", + " 'behavior_group_1': tracker # The name of the behavior (key), followed by the function that defines it\n", + " },\n", + " 'states': { # Dictionary of states updated by this mechanism\n", + " 'follow': add # The name of the state (key) followed by the function that updates it\n", + " }\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Running the engine\n", + "We can now recreate the Configuration object and rerun the experiment with the expanded configurations" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "single_proc: []\n" + ] + } + ], + "source": [ + "config = Configuration(sim_config=sim_config,\n", + " state_dict=initial_conditions,\n", + " seed=seeds,\n", + " exogenous_states=exogenous_states,\n", + " env_processes=env_processes,\n", + " mechanisms=mechanisms)\n", + "executor = Executor(exec_context, [config]) # Pass the configuration object inside an array\n", + "raw_result, tensor = executor.main() # The `main()` method returns a tuple; its first elements contains the raw results" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analyzing the results\n", + "And again we convert the raw results into a DataFrame for analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
signalfollow
count5.100000e+015.100000e+01
mean-3.800038e-17-3.755166e-17
std7.071068e-017.071068e-01
min-9.980267e-01-9.980267e-01
25%-6.845471e-01-6.845471e-01
50%0.000000e+000.000000e+00
75%6.845471e-016.845471e-01
max9.980267e-019.980267e-01
\n", + "
" + ], + "text/plain": [ + " signal follow\n", + "count 5.100000e+01 5.100000e+01\n", + "mean -3.800038e-17 -3.755166e-17\n", + "std 7.071068e-01 7.071068e-01\n", + "min -9.980267e-01 -9.980267e-01\n", + "25% -6.845471e-01 -6.845471e-01\n", + "50% 0.000000e+00 0.000000e+00\n", + "75% 6.845471e-01 6.845471e-01\n", + "max 9.980267e-01 9.980267e-01" + ] + }, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" }, @@ -174,16 +444,10 @@ "%matplotlib inline\n", "import pandas as pd\n", "from tabulate import tabulate\n", - "result = pd.DataFrame(run_raw_result)\n", - "result.plot('timestamp', ['signal','follow'])" + "df = pd.DataFrame(raw_result)\n", + "df.plot('timestamp', ['signal','follow'])\n", + "df[['signal','follow']].describe()" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": {