-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy path007_car.py
More file actions
executable file
·227 lines (189 loc) · 9.94 KB
/
007_car.py
File metadata and controls
executable file
·227 lines (189 loc) · 9.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
'''
Licensing Information: Please do not distribute or publish solutions to this
project. You are free to use and extend Driverless Car for educational
purposes. The Driverless Car project was developed at Stanford, primarily by
Chris Piech (piech@cs.stanford.edu). It was inspired by the Pacman projects.
'''
from engine.const import Const
import util, math, random, collections
# Class: ExactInference
# ---------------------
# Maintain and update a belief distribution over the probability of a car
# being in a tile using exact updates (correct, but slow times).
class ExactInference(object):
# Function: Init
# --------------
# Constructer that initializes an ExactInference object which has
# numRows x numCols number of tiles.
def __init__(self, numRows, numCols):
self.skipElapse = False ### ONLY USED BY GRADER.PY in case problem 3 has not been completed
# util.Belief is a class (constructor) that represents the belief for a single
# inference state of a single car (see util.py).
self.belief = util.Belief(numRows, numCols)
self.transProb = util.loadTransProb()
############################################################
# Problem 2:
# Function: Observe (update the probablities based on an observation)
# -----------------
# Takes |self.belief| and updates it based on the distance observation
# $d_t$ and your position $a_t$.
#
# - agentX: x location of your car (not the one you are tracking)
# - agentY: y location of your car (not the one you are tracking)
# - observedDist: true distance plus a mean-zero Gaussian with standard
# deviation Const.SONAR_STD
#
# Notes:
# - Convert row and col indices into locations using util.rowToY and util.colToX.
# - util.pdf: computes the probability density function for a Gaussian
# - Don't forget to normalize self.belief!
############################################################
def observe(self, agentX, agentY, observedDist):
for r in range(self.belief.getNumRows()):
y = util.rowToY(r)
for c in range(self.belief.getNumCols()):
bigP = self.belief.getProb(r,c)
dist = math.sqrt( ((agentX-util.colToX(c))**2 + (agentY-y)**2) )
lilP = util.pdf( observedDist, Const.SONAR_STD, dist )
self.belief.setProb(r, c, bigP * lilP)
self.belief.normalize()
############################################################
# Problem 3:
# Function: Elapse Time (propose a new belief distribution based on a learned transition model)
# ---------------------
# Takes |self.belief| and updates it based on the passing of one time step.
# Notes:
# - Use the transition probabilities in self.transProb, which gives all
# ((oldTile, newTile), transProb) key-val pairs that you must consider.
# - Other ((oldTile, newTile), transProb) pairs not in self.transProb have
# zero probabilities and do not need to be considered.
# - util.Belief is a class (constructor) that represents the belief for a single
# inference state of a single car (see util.py).
# - Be sure to update beliefs in self.belief ONLY based on the current self.belief distribution.
# Do NOT invoke any other updated belief values while modifying self.belief.
# - Use addProb and getProb to manipulate beliefs to add/get probabilities from a belief (see util.py).
# - Don't forget to normalize self.belief!
############################################################
def elapseTime(self):
if self.skipElapse: return ### ONLY FOR THE GRADER TO USE IN Problem 2
dontStopBelieving = util.Belief(self.belief.getNumRows(), self.belief.getNumCols(), 0.0)
for (old, new) in self.transProb.keys():
p = float(self.belief.getProb(old[0], old[1])) * float(self.transProb[(old, new)])
dontStopBelieving.addProb(new[0], new[1], p )
dontStopBelieving.normalize()
self.belief = dontStopBelieving
# Function: Get Belief
# ---------------------
# Returns your belief of the probability that the car is in each tile. Your
# belief probabilities should sum to 1.
def getBelief(self):
return self.belief
# Class: Particle Filter
# ----------------------
# Maintain and update a belief distribution over the probability of a car
# being in a tile using a set of particles.
class ParticleFilter(object):
NUM_PARTICLES = 200
# Function: Init
# --------------
# Constructer that initializes an ParticleFilter object which has
# numRows x numCols number of tiles.
def __init__(self, numRows, numCols):
self.belief = util.Belief(numRows, numCols)
# Load the transition probabilities and store them in a dict of Counters
# self.transProbDict[oldTile][newTile] = probability of transitioning from oldTile to newTile
self.transProb = util.loadTransProb()
self.transProbDict = dict()
for (oldTile, newTile) in self.transProb:
if not oldTile in self.transProbDict:
self.transProbDict[oldTile] = collections.Counter()
self.transProbDict[oldTile][newTile] = self.transProb[(oldTile, newTile)]
# Initialize the particles randomly
self.particles = collections.Counter()
potentialParticles = self.transProbDict.keys()
for i in range(self.NUM_PARTICLES):
particleIndex = int(random.random() * len(potentialParticles))
self.particles[potentialParticles[particleIndex]] += 1
self.updateBelief()
# Function: Update Belief
# ---------------------
# Updates |self.belief| with the probability that the car is in each tile
# based on |self.particles|, which is a Counter from particle to
# probability (which should sum to 1).
def updateBelief(self):
newBelief = util.Belief(self.belief.getNumRows(), self.belief.getNumCols(), 0)
for tile in self.particles:
newBelief.setProb(tile[0], tile[1], self.particles[tile])
newBelief.normalize()
self.belief = newBelief
############################################################
# Problem 4 (part a):
# Function: Observe:
# -----------------
# Takes |self.particles| and updates them based on the distance observation
# $d_t$ and your position $a_t$.
# This algorithm takes two steps:
# 1. Reweight the particles based on the observation.
# Concept: We had an old distribution of particles, we want to update these
# these particle distributions with the given observed distance by
# the emission probability.
# Think of the particle distribution as the unnormalized posterior
# probability where many tiles would have 0 probability.
# Tiles with 0 probabilities (no particles), we do not need to update.
# This makes particle filtering runtime to be O(|particles|).
# In comparison, exact inference (problem 2 + 3), most tiles would
# would have non-zero probabilities (though can be very small).
# 2. Resample the particles.
# Concept: Now we have the reweighted (unnormalized) distribution, we can now
# resample the particles and update where each particle should be at.
#
# - agentX: x location of your car (not the one you are tracking)
# - agentY: y location of your car (not the one you are tracking)
# - observedDist: true distance plus a mean-zero Gaussian with standard deviation Const.SONAR_STD
#
# Notes:
# - Create |self.NUM_PARTICLES| new particles during resampling.
# - To pass the grader, you must call util.weightedRandomChoice() once per new particle.
############################################################
def observe(self, agentX, agentY, observedDist):
w, newP = collections.Counter(), collections.Counter()
for p in self.particles:
dist = math.sqrt( (agentX-util.colToX(p[1]))**2 + (agentY-util.rowToY(p[0]))**2 )
w[p] = self.particles[p] * util.pdf(observedDist, Const.SONAR_STD, dist )
for n in range(self.NUM_PARTICLES):
newP[util.weightedRandomChoice(w)] += 1
self.particles = newP
# END_YOUR_CODE
self.updateBelief()
############################################################
# Problem 4 (part b):
# Function: Elapse Time (propose a new belief distribution based on a learned transition model)
# ---------------------
# Read |self.particles| (Counter) corresonding to time $t$ and writes
# |self.particles| corresponding to time $t+1$.
# This algorithm takes one step
# 1. Proposal based on the particle distribution at current time $t$:
# Concept: We have particle distribution at current time $t$, we want to
# propose the particle distribution at time $t+1$. We would like
# to sample again to see where each particle would end up using
# the transition model.
#
# Notes:
# - transition probabilities is now using |self.transProbDict|
# - Use util.weightedRandomChoice() to sample a new particle.
# - To pass the grader, you must loop over the particles using
# for tile in self.particles
# and call util.weightedRandomChoice() $once per particle$ on the tile.
############################################################
def elapseTime(self):
newPs = collections.Counter()
for p in self.particles:
for n in range(self.particles[p]):
newPs[util.weightedRandomChoice(self.transProbDict[p])] += 1
self.particles = newPs
# Function: Get Belief
# ---------------------
# Returns your belief of the probability that the car is in each tile. Your
# belief probabilities should sum to 1.
def getBelief(self):
return self.belief