|
592 | 592 | "where $\\alpha = \\frac{1}{2}$.\n", |
593 | 593 | "\n", |
594 | 594 | "## Implementation of multiple walks\n", |
| 595 | + "<div id=\"diffu:randomwalk:1D:multiplewalks\"></div>\n", |
595 | 596 | "\n", |
596 | 597 | "Our next task is to implement an ensemble of walks (for statistics,\n", |
597 | 598 | "see the section [Statistical considerations](#diffu:randomwalk:1D:EVar)) and also provide data from\n", |
|
647 | 648 | }, |
648 | 649 | { |
649 | 650 | "cell_type": "code", |
650 | | - "execution_count": 13, |
| 651 | + "execution_count": 216, |
651 | 652 | "metadata": {}, |
652 | 653 | "outputs": [], |
653 | 654 | "source": [ |
|
1060 | 1061 | }, |
1061 | 1062 | { |
1062 | 1063 | "cell_type": "code", |
1063 | | - "execution_count": 74, |
| 1064 | + "execution_count": 211, |
1064 | 1065 | "metadata": {}, |
1065 | 1066 | "outputs": [], |
1066 | 1067 | "source": [ |
|
1120 | 1121 | }, |
1121 | 1122 | { |
1122 | 1123 | "cell_type": "code", |
1123 | | - "execution_count": 72, |
| 1124 | + "execution_count": 212, |
1124 | 1125 | "metadata": {}, |
1125 | 1126 | "outputs": [], |
1126 | 1127 | "source": [ |
|
1146 | 1147 | "cell_type": "markdown", |
1147 | 1148 | "metadata": {}, |
1148 | 1149 | "source": [ |
1149 | | - "A vectorized version is desired. We follow the ideas from the section [Playing around with some code](#diffu:randomwalk:1D:code1). In fact, the only change to our Devito code is an extra `Dimension` added to our `TimeFunction`, representing the number of space dimensions. This can be represented as follows:" |
| 1150 | + "A vectorized version is desired. We follow the ideas from the section [Playing around with some code](#diffu:randomwalk:1D:code1). We need to add an extra `Dimension` to our `TimeFunction`, representing the number of space dimensions. We also need to generate `N*d` random values, which we can do using the `uniform` function from before and specifying the `size` argument as `N*d`. This can be represented as follows:" |
1150 | 1151 | ] |
1151 | 1152 | }, |
1152 | 1153 | { |
1153 | 1154 | "cell_type": "code", |
1154 | | - "execution_count": 73, |
| 1155 | + "execution_count": 219, |
1155 | 1156 | "metadata": {}, |
1156 | 1157 | "outputs": [], |
1157 | 1158 | "source": [ |
|
1165 | 1166 | " r = TimeFunction(name='r', dimensions=(x_d,d_d), shape=(N+1,d))\n", |
1166 | 1167 | " r.data[0] = x0\n", |
1167 | 1168 | " \n", |
1168 | | - " rs = random.uniform(0, 1, size=N)\n", |
1169 | | - " steps = Function(name='steps', dimensions=(x_d,), shape=(N+1,))\n", |
| 1169 | + " rs = random.uniform(0, 1, size=N*d).reshape(N,d)\n", |
| 1170 | + " steps = Function(name='steps', dimensions=(x_d,d_d), shape=(N+1,d))\n", |
1170 | 1171 | " steps.data[:N] = np.where(rs <= p, -1, 1)\n", |
1171 | 1172 | " \n", |
1172 | 1173 | " # The next value is computed using the previous value and the steps function at that point\n", |
|
1192 | 1193 | "\n", |
1193 | 1194 | "## Multiple random walks in any number of space dimensions\n", |
1194 | 1195 | "\n", |
1195 | | - "As we did in 1D, we extend one single walk to a number of walks (`num_walks`\n", |
1196 | | - "in the code).\n", |
1197 | | - "\n", |
1198 | | - "### Scalar code\n", |
1199 | | - "\n", |
1200 | | - "As always, we start with implementing the scalar case:" |
1201 | | - ] |
1202 | | - }, |
1203 | | - { |
1204 | | - "cell_type": "code", |
1205 | | - "execution_count": 49, |
1206 | | - "metadata": {}, |
1207 | | - "outputs": [], |
1208 | | - "source": [ |
1209 | | - "def random_walksdD(x0, N, p, num_walks=1, num_times=1,\n", |
1210 | | - " random=random):\n", |
1211 | | - " \"\"\"Simulate num_walks random walks from x0 with N steps.\"\"\"\n", |
1212 | | - " d = len(x0)\n", |
1213 | | - " position = np.zeros((N+1, d)) # Accumulated positions\n", |
1214 | | - " position2 = np.zeros((N+1, d)) # Accumulated positions**2\n", |
1215 | | - " # Histogram at num_times selected time points\n", |
1216 | | - " pos_hist = np.zeros((num_walks, num_times, d))\n", |
1217 | | - " pos_hist_times = [(N//num_times)*i for i in range(num_times)]\n", |
1218 | | - "\n", |
1219 | | - " for n in range(num_walks):\n", |
1220 | | - " num_times_counter = 0\n", |
1221 | | - " current_pos = np.array(x0, dtype=float)\n", |
1222 | | - " for k in range(N):\n", |
1223 | | - " if k in pos_hist_times:\n", |
1224 | | - " pos_hist[n,num_times_counter,:] = current_pos\n", |
1225 | | - " num_times_counter += 1\n", |
1226 | | - " # current_pos corresponds to step k+1\n", |
1227 | | - " for i in range(d):\n", |
1228 | | - " r = random.uniform(0, 1)\n", |
1229 | | - " if r <= p:\n", |
1230 | | - " current_pos[i] -= 1\n", |
1231 | | - " else:\n", |
1232 | | - " current_pos[i] += 1\n", |
1233 | | - " position [k+1,:] += current_pos\n", |
1234 | | - " position2[k+1,:] += current_pos**2\n", |
1235 | | - " return position, position2, pos_hist, np.array(pos_hist_times)" |
1236 | | - ] |
1237 | | - }, |
1238 | | - { |
1239 | | - "cell_type": "markdown", |
1240 | | - "metadata": {}, |
1241 | | - "source": [ |
1242 | | - "### Vectorized code\n", |
1243 | | - "\n", |
1244 | | - "Significant speed-ups can be obtained by vectorization. We get rid of\n", |
1245 | | - "the loops in the previous function and arrive at the following vectorized\n", |
1246 | | - "code." |
| 1196 | + "As we did in 1D, we extend one single walk to a number of walks (`num_walks` in the code). We can take a look at our function for multiple random walks (`random_walks1D`) from the [Implementation of multiple walks](#diffu:randomwalk:1D:multiplewalks) section. The changes we make here are similar to those we made for `random_walkdD_vec`, in that we add an extra `Dimension` to represent the number of space dimensions." |
1247 | 1197 | ] |
1248 | 1198 | }, |
1249 | 1199 | { |
1250 | 1200 | "cell_type": "code", |
1251 | | - "execution_count": 76, |
| 1201 | + "execution_count": 218, |
1252 | 1202 | "metadata": {}, |
1253 | 1203 | "outputs": [], |
1254 | 1204 | "source": [ |
1255 | 1205 | "def random_walksdD_vec(x0, N, p, num_walks=1, num_times=1, random=random):\n", |
1256 | | - " \"\"\"Vectorized version of random_walks1D; no loops.\"\"\"\n", |
| 1206 | + " \"\"\"Vectorized version of random_walksdD.\"\"\"\n", |
1257 | 1207 | " d = len(x0)\n", |
1258 | 1208 | " position = np.zeros((N+1, d)) # Accumulated positions\n", |
1259 | 1209 | " position2 = np.zeros((N+1, d)) # Accumulated positions**2\n", |
1260 | | - " walks = np.zeros((num_walks, N+1, d)) # Positions of each walk\n", |
1261 | | - " walks[:,0,:] = x0\n", |
1262 | 1210 | " # Histogram at num_times selected time points\n", |
1263 | 1211 | " pos_hist = np.zeros((num_walks, num_times, d))\n", |
1264 | 1212 | " pos_hist_times = [(N//num_times)*i for i in range(num_times)]\n", |
1265 | 1213 | "\n", |
1266 | | - " r = random.uniform(0, 1, size=N*num_walks*d)\n", |
1267 | | - " steps = np.where(r <= p, -1, 1).reshape(num_walks, N, d)\n", |
1268 | | - " walks[:,1:,:] = x0 + np.cumsum(steps, axis=1)\n", |
1269 | | - " position = np.sum(walks, axis=0)\n", |
1270 | | - " position2 = np.sum(walks**2, axis=0)\n", |
1271 | | - " pos_hist[:,:,:] = walks[:,pos_hist_times,:]\n", |
| 1214 | + " # Create and initialise our TimeFunction r\n", |
| 1215 | + " x_d = Dimension(name='x_d')\n", |
| 1216 | + " t_d = Dimension(name='t_d')\n", |
| 1217 | + " d_d = Dimension(name='d_d')\n", |
| 1218 | + " r = TimeFunction(name='r', dimensions=(x_d, t_d, d_d), shape=(N+1, num_walks, d))\n", |
| 1219 | + " # Setting each walk's first element to x0\n", |
| 1220 | + " r.data[0] = x0\n", |
| 1221 | + " \n", |
| 1222 | + " steps = Function(name='steps', dimensions=(x_d,t_d,d_d), shape=(N+1,num_walks,d))\n", |
| 1223 | + " \n", |
| 1224 | + " # Populating steps with -1 if value in rs <= p at that point and 1 otherwise\n", |
| 1225 | + " rs = random.uniform(0, 1, size=N*num_walks*d).reshape(num_walks, N, d)\n", |
| 1226 | + " for n in range(num_walks):\n", |
| 1227 | + " steps.data[:N, n] = np.where(rs[n] <= p, -1, 1)\n", |
| 1228 | + " \n", |
| 1229 | + " # Creating and applying operator that contains equation for adding steps\n", |
| 1230 | + " eq = Eq(r.forward, r + steps)\n", |
| 1231 | + " op = Operator(eq)\n", |
| 1232 | + " op.apply()\n", |
| 1233 | + " \n", |
| 1234 | + " # Summing over data to give positions\n", |
| 1235 | + " position = np.sum(r.data, axis=1) # Accumulated positions\n", |
| 1236 | + " position2 = np.sum(r.data**2, axis=1) # Accumulated positions**2\n", |
| 1237 | + " \n", |
| 1238 | + " for k in range(num_walks):\n", |
| 1239 | + " pos_hist[k,:] = r.data[pos_hist_times,k]\n", |
| 1240 | + " \n", |
1272 | 1241 | " return position, position2, pos_hist, np.array(pos_hist_times)" |
1273 | 1242 | ] |
1274 | 1243 | }, |
1275 | | - { |
1276 | | - "cell_type": "code", |
1277 | | - "execution_count": 77, |
1278 | | - "metadata": {}, |
1279 | | - "outputs": [], |
1280 | | - "source": [] |
1281 | | - }, |
1282 | | - { |
1283 | | - "cell_type": "code", |
1284 | | - "execution_count": null, |
1285 | | - "metadata": {}, |
1286 | | - "outputs": [], |
1287 | | - "source": [] |
1288 | | - }, |
1289 | 1244 | { |
1290 | 1245 | "cell_type": "markdown", |
1291 | 1246 | "metadata": {}, |
|
0 commit comments