No description has been provided for this image

Random walks¶

Faisal Qureshi
faisal.qureshi@ontariotechu.ca
http://www.vclab.ca

Copyright information¶

© Faisal Qureshi

License¶

No description has been provided for this image This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.
In [1]:
import numpy as np
import random
import matplotlib.pyplot as plt

Location class¶

In [2]:
class Location:

    def __init__(self, loc):
        self.loc = np.array(loc)

    def move_by(self, l):
        return Location(np.add(self.loc, l.loc))

    def dist_from(self, o):
        return np.sqrt(np.sum((self.loc - o.loc)**2))

    def __str__(self):
        return str(self.loc)

Testing Location class¶

In [3]:
# Testing Location class
a = Location([0,1])
b = Location([2,4])

print ('Location a', a)
print ('Location b', b)
print ('Distance between a and b', a.dist_from(b))
print ('Move', a, 'by [3,4] gets us', a.move_by(Location([3,4])))
Location a [0 1]
Location b [2 4]
Distance between a and b 3.605551275463989
Move [0 1] by [3,4] gets us [3 5]

Field class¶

In [4]:
class Field:

    def __init__(self):
        self.walkers = {}

    # Must override this method to ensure that Field is properly resetted
    def reset(self):
        self.walkers = {}
        
    def add(self, walker, loc):
        """
        Add a walker at location loc
        """        
        if walker in self.walkers:
            raise ValueError('Walker already present')
        else:
            self.walkers[walker] = loc

    def move(self, walker):
        """
        Updates walker's location by its step
        """
        if not walker in self.walkers:
            raise ValueError('Cannot find this walker')
        cur_loc = self.walkers[walker]
        step = walker.step() 
        new_loc = cur_loc.move_by(step)
        self.walkers[walker] = new_loc

    def get_loc(self, walker):
        """
        Returns the location of this walker
        """
        if not walker in self.walkers:
            raise ValueError('Cannot find this walker')
        return self.walkers[walker]

Walker class¶

In [5]:
class Walker:

    def __init__(self, name):
        self.name = name

    # Over-ride this function to create different Walkers.
    def select_a_step(self, step_choices):
        return random.choice(step_choices)

    # Over-ride this function to create different Walkers
    def step(self): 
        step_choices = [Location([0,1]), Location([0,-1]), Location([1,0]), Location([-1,0])]
        return self.select_a_step(step_choices)

    def __str__(self):
        return self.name

walk method¶

Simulates a single random walk

In [6]:
def walk(f, w, num_steps, show_locations=False):
    """
    Returns distance from the staring location and the ending location
    """
    
    start = f.get_loc(w)          # Get walker's starting position
    for s in range(num_steps):    # Now move walker num_steps time
        f.move(w)
        if show_locations:
            print(w.name, '(', s, ')', f.get_loc(w))
    return start.dist_from(f.get_loc(w)), f.get_loc(w).loc  # Compute distance between starting and ending location
In [7]:
random.seed(0)

f = Field()
w = Walker('zombie')
f.add(w, Location([0,0]))
print (walk(f, w, 10, False))
(np.float64(2.0), array([-2,  0]))

simulate_walks method¶

Simulating multiple runs of a fixed length random walk

In [8]:
def simulate_walks(num_steps, num_trials, start_loc, field, walker):
    """
    Simulations a num_steps long random walk for num_trials times. 
    Returns distances and ending locations for each trial
    """
    
    start = start_loc
    distances = np.array([0.0])
    ending_locations = start.loc

    zombie = walker
    f = field    
    for t in range(num_trials):
        f.reset()
        f.add(zombie, start)
        d, e = walk(f, zombie, num_steps)
        distances = np.vstack([distances, d])
        ending_locations = np.vstack([ending_locations, e])
    return distances, ending_locations
In [9]:
start_loc = Location([0,0])
num_steps = 1000
num_trials = 1000

d, e = simulate_walks(num_steps=num_steps, num_trials=num_trials, start_loc=start_loc, field=Field(), walker=Walker('zombie'))
In [10]:
print ('average distance', np.mean(d))
average distance 28.216216891337908
In [11]:
plt.figure(figsize=(4,4))
plt.scatter(e[1:,0],e[1:,1],alpha=0.1)
plt.axis('equal')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Ending locations')
plt.show()
No description has been provided for this image
In [12]:
plt.figure(figsize=(4,4))
plt.hist(d[1:])
plt.ylabel('# Trials')
plt.xlabel('Distances')
plt.title('Distances')
plt.show()
No description has been provided for this image
In [13]:
class FieldWithTraps(Field):
    def __init__(self, w, h, num_traps):
        Field.__init__(self)
        
        self.w = w
        self.h = h
        self.num_traps = num_traps
        self.traps = []
        for i in range(self.num_traps):
            x = random.random()*self.w
            y = random.random()*self.h
            self.traps.append(Location([x,y]))
        
    def reset(self):
        Field.reset(self)
        self.traps = []
        for i in range(self.num_traps):
            x = random.random()*self.w
            y = random.random()*self.h
            self.traps.append(Location([x,y]))

    def move(self, walker):
        if not walker in self.walkers:
            raise ValueError('Cannot find this walker')
        step = walker.step() # Notice that step is a delta Location
        new_loc = self.walkers[walker].move_by(step)
        
        for l in self.traps:
            if np.all(l.loc == new_loc.loc):
                x = random.random()*w
                y = random.random()*h
                self.walkers[walker] = Location([x,y])
                return
        self.walkers[walker] = new_loc
In [14]:
d, e = simulate_walks(num_steps=100, num_trials=100, start_loc=Location([0,0]), field=FieldWithTraps(30,30,300), walker=Walker('zombie'))
print ('average distance', np.mean(d))
average distance 8.896677422893275
In [15]:
plt.figure(figsize=(7,7))
plt.scatter(e[1:,0],e[1:,1])
plt.axis('equal')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Ending locations')
plt.show()

plt.figure(figsize=(7,7))
plt.hist(d)
plt.ylabel('# Trials')
plt.xlabel('Distances')
plt.title('Distances')
plt.show()
No description has been provided for this image
No description has been provided for this image
In [16]:
class WalkerUp(Walker):
    def __init__(self, name):
        Walker.__init__(self, name)
    
    def step(self): 
        step_choices = [Location([0,1.1]), Location([0,-.9]), Location([1,0]), Location([-1,0])]
        return self.select_a_step(step_choices)    

d, e = simulate_walks(num_steps=1000, num_trials=500, start_loc=Location([0,0]), field=Field(), walker=WalkerUp('baloon'))
print ('average distance', np.mean(d))

plt.figure(figsize=(7,7))
plt.scatter(e[1:,0],e[1:,1])
plt.axis('equal')
plt.xlabel('x')
plt.ylabel('y')
plt.xlim(-200,200)
plt.ylim(-200,200)
plt.title('Ending locations')
plt.show()

plt.figure(figsize=(7,7))
plt.hist(d)
plt.ylabel('# Trials')
plt.xlabel('Distances')
plt.title('Distances')
plt.show()
Ignoring fixed y limits to fulfill fixed data aspect with adjustable data limits.
average distance 56.10079027173256
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [ ]: