Material for ASPP 2024

This commit is contained in:
Pietro Berkes 2024-08-27 15:52:41 +03:00
commit 849682b13b
97 changed files with 8170 additions and 0 deletions

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,81 @@
import numpy as np
import matplotlib.pyplot as plt
def sample_next_step(current_i, current_j, sigma_i, sigma_j, context_map,
random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a next-step
# probability map
size = context_map.shape[0]
next_step_map = next_step_proposal(current_i, current_j, sigma_i, sigma_j,
size)
next_step_probability = compute_next_step_probability(next_step_map,
context_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(next_step_probability)
cumulative_map = cumulative_map.reshape(next_step_probability.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
def next_step_proposal(current_i, current_j, sigma_i, sigma_j, size):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def compute_next_step_probability(next_step_map, context_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability
def create_context_map(size, map_type='flat'):
""" Create a fixed context map. """
if map_type == 'flat':
context_map = np.ones((size, size))
elif map_type == 'hills':
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
elif map_type == 'labyrinth':
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map /= context_map.sum()
return context_map
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,91 @@
import numpy as np
import matplotlib.pyplot as plt
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, size, map_type='flat'):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = size
if map_type == 'flat':
context_map = np.ones((size, size))
elif map_type == 'hills':
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
elif map_type == 'labyrinth':
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:size, 0:size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()

View file

@ -0,0 +1,81 @@
import numpy as np
import matplotlib.pyplot as plt
def sample_next_step(current_i, current_j, sigma_i, sigma_j, context_map,
random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a next-step
# probability map
size = context_map.shape[0]
next_step_map = next_step_proposal(current_i, current_j, sigma_i, sigma_j,
size)
next_step_probability = compute_next_step_probability(next_step_map,
context_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(next_step_probability)
cumulative_map = cumulative_map.reshape(next_step_probability.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
def next_step_proposal(current_i, current_j, sigma_i, sigma_j, size):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def compute_next_step_probability(next_step_map, context_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability
def create_context_map(size, map_type='flat'):
""" Create a fixed context map. """
if map_type == 'flat':
context_map = np.ones((size, size))
elif map_type == 'hills':
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
elif map_type == 'labyrinth':
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map /= context_map.sum()
return context_map
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,83 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, size, map_type='flat'):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = size
if map_type == 'flat':
context_map = np.ones((size, size))
elif map_type == 'hills':
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
elif map_type == 'labyrinth':
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:size, 0:size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

View file

@ -0,0 +1,101 @@
import numpy as np
import matplotlib.pyplot as plt
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, size, map_type='flat'):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = size
if map_type == 'flat':
context_map = np.ones((size, size))
elif map_type == 'hills':
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
elif map_type == 'labyrinth':
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:size, 0:size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
def plot_trajectory(self, trajectory):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(self.context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(self, trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

View file

@ -0,0 +1,173 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"# 1. Take a look at this (working) code\n",
"\n",
"... and run it. We discussed that the `context_map` varies independently of the walker. Identify the part of the code that will be affected by this change."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2022-08-18T09:50:40.616906Z",
"start_time": "2022-08-18T11:50:40.181358+02:00"
},
"execution": {
"iopub.execute_input": "2022-08-20T06:27:54.689Z",
"iopub.status.busy": "2022-08-20T06:27:54.685Z",
"iopub.status.idle": "2022-08-20T06:27:55.297Z",
"shell.execute_reply": "2022-08-20T06:27:55.319Z"
},
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"\n",
"from plotting import plot_trajectory, plot_trajectory_hexbin\n",
"from walker import Walker\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": false,
"source_hidden": false
},
"nteract": {
"transient": {
"deleting": false
}
}
},
"outputs": [],
"source": [
"# Create a Walker instance\n",
"walker = Walker(sigma_i=3, sigma_j=4, size=200, map_type='hills')\n",
"\n",
"# Sample a next step 1000 times\n",
"i, j = 100, 50\n",
"trajectory = []\n",
"for _ in range(1000):\n",
" i, j = walker.sample_next_step(i, j)\n",
" trajectory.append((i, j))\n",
"\n",
"plot_trajectory(trajectory, walker.context_map)"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"# 2. Modify the above code to reflect the idea of a separate context_map module\n",
"\n",
"1. how would the import statement change as a result of needing a separate context_map module?\n",
"2. what input arguments do the context_map functions need to take?\n",
"3. how does the initialization of the walker change?\n",
" - i.e. instead of \"map_type\"\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"# 3. (optional) Actually break out the context map initialization\n",
"1. Move context map initialization to three functions in a separate `context_map.py` module which all return a `context_map` array\n",
"2. Modify the constructor of Walker to take a `context_map` array instead of a `map_type`\n",
"3. Modify this notebook to use the new code and see if the code you wrote works!\n",
"4. Try to run all the types:\n",
" - Run one simulation with a flat context map\n",
" - Run one simulation with a hill context map\n",
" - Run one simulation with a labyrinth context map"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"hide_input": false,
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.3"
},
"nteract": {
"version": "0.28.0"
},
"toc": {
"nav_menu": {
"height": "12px",
"width": "252px"
},
"navigate_menu": true,
"number_sections": true,
"sideBar": true,
"threshold": 4,
"toc_cell": false,
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 1
}

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,37 @@
""" CONTEXT MAP BUILDERS """
import numpy as np
def flat_context_map(size):
""" A context map where all positions are equally likely. """
return np.ones((size, size))
def hills_context_map(size):
""" A context map with bumps and valleys. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
return context_map
def labyrinth_context_map(size):
""" A context map that looks like a labyrinth. """
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
return context_map

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,60 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, context_map):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = context_map.shape[0]
# Make sure that the context map is normalized
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:self.size, 0:self.size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

View file

@ -0,0 +1,83 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, size, map_type='flat'):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = size
if map_type == 'flat':
context_map = np.ones((size, size))
elif map_type == 'hills':
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
elif map_type == 'labyrinth':
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:size, 0:size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,37 @@
""" CONTEXT MAP BUILDERS """
import numpy as np
def flat_context_map(size):
""" A context map where all positions are equally likely. """
return np.ones((size, size))
def hills_context_map(size):
""" A context map with bumps and valleys. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
return context_map
def labyrinth_context_map(size):
""" A context map that looks like a labyrinth. """
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
return context_map

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,37 @@
""" CONTEXT MAP BUILDERS """
import numpy as np
def flat_context_map(size):
""" A context map where all positions are equally likely. """
return np.ones((size, size))
def hills_context_map(size):
""" A context map with bumps and valleys. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
return context_map
def labyrinth_context_map(size):
""" A context map that looks like a labyrinth. """
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
return context_map

View file

@ -0,0 +1,25 @@
""" Functions to compute next step proposal maps. """
import numpy as np
def gaussian_next_step_proposal(current_i, current_j, size, sigma_i, sigma_j):
""" Gaussian next step proposal. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def square_next_step_proposal(current_i, current_j, size, width):
""" Square next step proposal. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
inside_mask = (np.abs(grid_ii - current_i) <= width // 2) & (np.abs(grid_jj - current_j) <= width // 2)
p_next_step = inside_mask / inside_mask.sum()
return p_next_step

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,59 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, context_map, next_step_proposal, next_step_proposal_arguments):
self.size = context_map.shape[0]
# Make sure that the context map is normalized
context_map /= context_map.sum()
self.context_map = context_map
self.next_step_proposal = next_step_proposal
self.next_step_proposal_arguments = next_step_proposal_arguments
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self.next_step_proposal(
current_i, current_j, self.size, **self.next_step_proposal_arguments)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

View file

@ -0,0 +1,60 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, context_map):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = context_map.shape[0]
# Make sure that the context map is normalized
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:self.size, 0:self.size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,39 @@
""" CONTEXT MAP BUILDERS """
import numpy as np
def flat_context_map_builder(size):
""" A context map where all positions are equally likely. """
return np.ones((size, size))
def hills_context_map_builder(size):
""" A context map with bumps and valleys. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
return context_map
def labyrinth_context_map_builder(size):
""" A context map that looks like a labyrinth. """
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
return context_map

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,42 @@
import json
import time
import git
import numpy as np
import context_maps
from walker import Walker
# Use the following parameters to simulate and save a trajectory of the walker
seed = 42
sigma_i = 3
sigma_j = 4
size = 200
i, j = (50, 100)
n_iterations = 1000
# USE map_type hills
random_state = np.random.RandomState(seed)
# STEP 1: Create a context map
# STEP 2: Create a Walker
# STEP 3: Simulate the walk
# STEP 4: Save the trajectory
curr_time = time.strftime("%Y%m%d-%H%M%S")
# save the npy file here!
# STEP 5: Save the metadata
# lookup git repository
repo = git.Repo(search_parent_directories=True)
sha = repo.head.object.hexsha
with open('meta.txt', 'w') as f:
f.write(f'I estimated parameters at {curr_time}.\n')
f.write(f'The git repo was at commit {sha}')
# you can add any other information you want here!

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,40 @@
""" CONTEXT MAP BUILDERS """
import numpy as np
def flat_context_map_builder(size):
""" A context map where all positions are equally likely. """
return np.ones((size, size))
def hills_context_map_builder(size):
""" A context map with bumps and valleys. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
return context_map
def labyrinth_context_map_builder(size):
""" A context map that looks like a labyrinth. """
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
return context_map

View file

@ -0,0 +1,2 @@
I estimated parameters at 20230628-192022.
The git repo was at commit 6a26566a46593a650ebfc86ebdbb28ee78ace079

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,46 @@
import json
import time
import git
import numpy as np
import context_maps
from walker import Walker
# Use the following parameters to simulate and save a trajectory of the walker
seed = 42
sigma_i = 3
sigma_j = 4
size = 200
i, j = (50, 100)
n_iterations = 1000
# USE map_type hills
random_state = np.random.RandomState(seed)
# STEP 1: Create a context map
context_map = context_maps.hills_context_map_builder(size)
# STEP 2: Create a Walker
walker = Walker(sigma_i, sigma_j, context_map)
# STEP 3: Simulate the walk
trajectory = []
for _ in range(n_iterations):
i, j = walker.sample_next_step(i, j, random_state)
trajectory.append((i, j))
# STEP 4: Save the trajectory
curr_time = time.strftime("%Y%m%d-%H%M%S")
np.save(f"sim_{curr_time}", trajectory)
# STEP 5: Save the metadata
# lookup git repository
repo = git.Repo(search_parent_directories=True)
sha = repo.head.object.hexsha
with open('meta.txt', 'w') as f:
f.write(f'I estimated parameters at {curr_time}.\n')
f.write(f'The git repo was at commit {sha}')

View file

@ -0,0 +1,60 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, context_map):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = context_map.shape[0]
# Make sure that the context map is normalized
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:self.size, 0:self.size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

View file

@ -0,0 +1,60 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, context_map):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = context_map.shape[0]
# Make sure that the context map is normalized
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:self.size, 0:self.size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

View file

@ -0,0 +1,39 @@
""" CONTEXT MAP BUILDERS """
import numpy as np
def flat_context_map_builder(size):
""" A context map where all positions are equally likely. """
return np.ones((size, size))
def hills_context_map_builder(size):
""" A context map with bumps and valleys. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
return context_map
def labyrinth_context_map_builder(size):
""" A context map that looks like a labyrinth. """
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
return context_map

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,46 @@
import json
import time
import git
import numpy as np
import context_maps
from walker import Walker
# Use the following parameters to simulate and save a trajectory of the walker
seed = 42
sigma_i = 3
sigma_j = 4
size = 200
i, j = (50, 100)
n_iterations = 1000
# USE map_type hills
random_state = np.random.RandomState(seed)
# STEP 1: Create a context map
context_map = context_maps.hills_context_map_builder(size)
# STEP 2: Create a Walker
walker = Walker(sigma_i, sigma_j, context_map)
# STEP 3: Simulate the walk
trajectory = []
for _ in range(n_iterations):
i, j = walker.sample_next_step(i, j, random_state)
trajectory.append((i, j))
# STEP 4: Save the trajectory
curr_time = time.strftime("%Y%m%d-%H%M%S")
np.save(f"sim_{curr_time}", trajectory)
# STEP 5: Save the metadata
# lookup git repository
repo = git.Repo(search_parent_directories=True)
sha = repo.head.object.hexsha
with open('meta.txt', 'w') as f:
f.write(f'I estimated parameters at {curr_time}.\n')
f.write(f'The git repo was at commit {sha}')

View file

@ -0,0 +1,46 @@
""" CONTEXT MAP BUILDERS """
import numpy as np
def flat_context_map_builder(size):
""" A context map where all positions are equally likely. """
return np.ones((size, size))
def hills_context_map_builder(size):
""" A context map with bumps and valleys. """
grid_ii, grid_jj = np.mgrid[0:size, 0:size]
i_waves = np.sin(grid_ii / 130) + np.sin(grid_ii / 10)
i_waves /= i_waves.max()
j_waves = np.sin(grid_jj / 100) + np.sin(grid_jj / 50) + \
np.sin(grid_jj / 10)
j_waves /= j_waves.max()
context_map = j_waves + i_waves
return context_map
def labyrinth_context_map_builder(size):
""" A context map that looks like a labyrinth. """
context_map = np.ones((size, size))
context_map[50:100, 50:60] = 0
context_map[20:89, 80:90] = 0
context_map[90:120, 0:10] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
context_map[50:60, 50:200] = 0
context_map[179:189, 80:130] = 0
context_map[110:120, 0:190] = 0
context_map[120:size, 30:40] = 0
context_map[180:190, 50:60] = 0
return context_map
# Register map builders
map_builders = {
"flat": flat_context_map_builder,
"hills": hills_context_map_builder,
"labyrinth": labyrinth_context_map_builder,
}

View file

@ -0,0 +1,10 @@
{
"seed": 42,
"sigma_i": 3,
"sigma_j": 4,
"size": 200,
"map_type": "hills",
"start_i": 50,
"start_j": 100,
"n_iterations": 1000
}

View file

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
import numpy as np
def plot_trajectory(trajectory, context_map):
""" Plot a trajectory over a context map. """
trajectory = np.asarray(trajectory)
plt.matshow(context_map)
plt.plot(trajectory[:, 1], trajectory[:, 0], color='r')
plt.show()
def plot_trajectory_hexbin(trajectory):
""" Plot an hexagonal density map of a trajectory. """
trajectory = np.asarray(trajectory)
with plt.rc_context({'figure.figsize': (4, 4), 'axes.labelsize': 16,
'xtick.labelsize': 14, 'ytick.labelsize': 14}):
plt.hexbin(trajectory[:, 1], trajectory[:, 0], gridsize=30,
extent=(0, 200, 0, 200), edgecolors='none', cmap='Reds')
plt.gca().invert_yaxis()
plt.xlabel('X')
plt.ylabel('Y')

View file

@ -0,0 +1,42 @@
import json
import time
import git
import numpy as np
from walker import Walker
from context_maps import map_builders
with open("inputs.json", 'r') as f:
inputs = json.load(f)
random_state = np.random.RandomState(inputs["seed"])
n_iterations = inputs["n_iterations"]
context_map_builder = map_builders[inputs["map_type"]]
context_map = context_map_builder(inputs["size"])
walker = Walker(inputs["sigma_i"], inputs["sigma_j"], context_map)
trajectory = []
for _ in range(n_iterations):
i, j = walker.sample_next_step(inputs["start_i"], inputs["start_j"],
random_state)
trajectory.append((i, j))
# STEP 4: Save the trajectory
curr_time = time.strftime("%Y%m%d-%H%M%S")
np.save(f"sim_{curr_time}", trajectory)
# STEP 5: Save the metadata
# lookup git repository
repo = git.Repo(search_parent_directories=True)
sha = repo.head.object.hexsha
with open('meta.txt', 'w') as f:
f.write(f'I estimated parameters at {curr_time}.\n')
f.write(f'The git repo was at commit {sha}')

View file

@ -0,0 +1,60 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, context_map):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = context_map.shape[0]
# Make sure that the context map is normalized
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:self.size, 0:self.size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability

View file

@ -0,0 +1,60 @@
import numpy as np
class Walker:
""" The Walker knows how to walk at random on a context map. """
def __init__(self, sigma_i, sigma_j, context_map):
self.sigma_i = sigma_i
self.sigma_j = sigma_j
self.size = context_map.shape[0]
# Make sure that the context map is normalized
context_map /= context_map.sum()
self.context_map = context_map
# Pre-compute a 2D grid of coordinates for efficiency
self._grid_ii, self._grid_jj = np.mgrid[0:self.size, 0:self.size]
# --- Walker public interface
def sample_next_step(self, current_i, current_j, random_state=np.random):
""" Sample a new position for the walker. """
# Combine the next-step proposal with the context map to get a
# next-step probability map
next_step_map = self._next_step_proposal(current_i, current_j)
selection_map = self._compute_next_step_probability(next_step_map)
# Draw a new position from the next-step probability map
r = random_state.rand()
cumulative_map = np.cumsum(selection_map)
cumulative_map = cumulative_map.reshape(selection_map.shape)
i_next, j_next = np.argwhere(cumulative_map >= r)[0]
return i_next, j_next
# --- Walker non-public interface
def _next_step_proposal(self, current_i, current_j):
""" Create the 2D proposal map for the next step of the walker. """
# 2D Gaussian distribution , centered at current position,
# and with different standard deviations for i and j
grid_ii, grid_jj = self._grid_ii, self._grid_jj
sigma_i, sigma_j = self.sigma_i, self.sigma_j
rad = (
(((grid_ii - current_i) ** 2) / (sigma_i ** 2))
+ (((grid_jj - current_j) ** 2) / (sigma_j ** 2))
)
p_next_step = np.exp(-(rad / 2.0)) / (2.0 * np.pi * sigma_i * sigma_j)
return p_next_step / p_next_step.sum()
def _compute_next_step_probability(self, next_step_map):
""" Compute the next step probability map from next step proposal and
context map. """
next_step_probability = next_step_map * self.context_map
next_step_probability /= next_step_probability.sum()
return next_step_probability