I'm having some problems with operator overloading. If you could check please.
The code:
import math
class Mat4:
cells = [ [0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0] ]
#staticmethod
def DET2(a, b, c, d):
return a * d - b * c
#staticmethod
def DET3(a,b,c, d,e,f, g,h,i):
return a * Mat4.DET2(e,f,h,i) - b * Mat4.DET2(d,f,g,i) + c * Mat4.DET2(d,e,g,h)
#staticmethod
def DET4(a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p):
return ( a * Mat4.DET3(f,g,h,j,k,l,n,o,p) - b * Mat4.DET3(e,g,h,i,k,l,m,o,p) + c * Mat4.DET3(e,f,h,i,j,l,m,n,p) - d * Mat4.DET3(e,f,g,i,j,k,m,n,o))
#staticmethod
def Scale(factor):
res = Mat4()
res.cells = [ [factor,0, 0, 0],
[0, factor, 0, 0],
[0, 0, factor, 0],
[0, 0, 0, 1] ]
return res
def __mul__(self, other):
if isinstance(other, Mat4):
print(self.cells)
print(other.cells)
print("h\n")
out = Mat4()
for row_left in range(4):
for col_right in range(4):
out.cells[row_left][col_right] = 0
for k in range(4):
out.cells[row_left][col_right] += self.cells[row_left][k] * other.cells[k][col_right]
return out
if isinstance(other, int) or isinstance(other, float):
for i in range(4):
for j in range(4):
self.cells[i][j] *= other
return self
def __truediv__(self, other):
print(self.cells)
print(other.GetInversed().cells)
print("pl\n")
return self * other.GetInversed()
#staticmethod
def Identity():
return Mat4.Scale(1)
#staticmethod
def RotationX(angle):
sinTheta = math.sin(angle)
cosTheta = math.cos(angle)
res = Mat4()
res.cells = [ [1, 0, 0, 0],
[0, cosTheta, -sinTheta, 0],
[0, sinTheta, cosTheta, 0],
[0, 0, 0, 1] ]
return res
def GetInversed(self):
a = self.cells[0][0]
b = self.cells[0][1]
c = self.cells[0][2]
d = self.cells[0][3]
e = self.cells[1][0]
f = self.cells[1][1]
g = self.cells[1][2]
h = self.cells[1][3]
i = self.cells[2][0]
j = self.cells[2][1]
k = self.cells[2][2]
l = self.cells[2][3]
m = self.cells[3][0]
n = self.cells[3][1]
o = self.cells[3][2]
p = self.cells[3][3]
min_a = Mat4.DET3(f,g,h,j,k,l,n,o,p)
min_b = Mat4.DET3(e,g,h,i,k,l,m,o,p)
min_c = Mat4.DET3(e,f,h,i,j,l,m,n,p)
min_d = Mat4.DET3(e,f,g,i,j,k,m,n,o)
det_m = a * min_a - b * min_b + c * min_c - d * min_d
res = Mat4()
res.cells[0][0] = min_a
res.cells[1][0] = -min_b
res.cells[2][0] = min_c
res.cells[3][0] = -min_d
res.cells[0][1] = -Mat4.DET3(b,c,d,j,k,l,n,o,p)
res.cells[1][1] = Mat4.DET3(a,c,d,i,k,l,m,o,p)
res.cells[2][1] = -Mat4.DET3(a,b,d,i,j,l,m,n,p)
res.cells[3][1] = Mat4.DET3(a,b,c,i,j,k,m,n,o)
res.cells[0][2] = Mat4.DET3(b,c,d,f,g,h,n,o,p)
res.cells[1][2] = -Mat4.DET3(a,c,d,e,g,h,m,o,p)
res.cells[2][2] = Mat4.DET3(a,b,d,e,f,h,m,n,p)
res.cells[3][2] = -Mat4.DET3(a,b,c,e,f,g,m,n,o)
res.cells[0][3] = -Mat4.DET3(b,c,d,f,g,h,j,k,l)
res.cells[1][3] = Mat4.DET3(a,c,d,e,g,h,i,k,l)
res.cells[2][3] = -Mat4.DET3(a,b,d,e,f,h,i,j,l)
res.cells[3][3] = Mat4.DET3(a,b,c,e,f,g,i,j,k)
return res * ( 1.0 / det_m)
def main():
rotMat = Mat4().RotationX(50)
scaMat = Mat4().Scale(3)
mRes = (rotMat * scaMat) / rotMat
print(mRes.cells)
if __name__ == "__main__":
main()
The result I'm getting:
mRes = [[0.0, 0.0, 0.0, 0.0], [0.0, -0.068840563856158, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]]
The result I should get, because rotation gets subtracted and only the scaling has left:
mRes = [[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 3, 0], [0, 0, 0, 1]]
The problem is with __mul__ operator because it's having other and self parameters to store same values, but address is not the same:
For some reasons the first time multiplication happens mRes = (rotMat * scaMat) is okay, but the problems comes when the resulted matrix from the division calls division operator, which also calls multiplication operator.
Related
I am trying to warp an image based of the orientation of the camera relative to an aruco marker in the middle of the image. I have managed to get the translation part working but the rotation element is not working. It seems like the image isn't rotating about the centre of the aruco axis. The reference image was taken straight on and the warped image is overlayed.
# Find centre of the marker
top_left_x = (corners[0][0][0, 0])
top_left_y = (corners[0][0][0, 1])
top_right_x = (corners[0][0][1, 0])
top_right_y = (corners[0][0][1, 1])
bottom_right_x = (corners[0][0][2, 0])
bottom_right_y = (corners[0][0][2, 1])
bottom_left_x = (corners[0][0][3, 0])
bottom_left_y = (corners[0][0][3, 1])
# Compare this to the centre of the image to calculate the offset
mid_x = top_right_x - (top_right_x - top_left_x) / 2
mid_y = bottom_left_y - (bottom_left_y - top_left_y) / 2
x_centre = 960
y_centre = 540
x_offset = x_centre - mid_x
y_offset = y_centre - mid_y
if x_centre > mid_x: # gone right
x_offset = 1 * (x_centre - mid_x) # correction to the left
if x_centre < mid_x: # gone left
x_offset = -1 * (mid_x - x_centre) # correction to the right
if y_centre > mid_y: # gone down
y_offset = 1 * (y_centre - mid_y) # correction to the left
if y_centre < mid_y: # gone left
y_offset = -1 * (mid_y - y_centre) # correction to the right
current_z_distance = (math.sqrt((pos_camera[0]**2) + (pos_camera[1]**2) +
(pos_camera[2]**2))) * 15.4
img = cv2.imread('Corrected.png')
corrected_z = 31 # Distance when image was taken
initial_z_distance = corrected_z * 15.4 # Pixels
delta_z = (initial_z_distance - current_z_distance)
scale_factor = current_z_distance / initial_z_distance # how much larger the image
now is. Used for scaling
z_translation = delta_z * 1.54 # how much the image has moved. negative for going
backwards
z_translation = 0
z_axis = 960 / scale_factor
proj2dto3d = np.array([[1, 0, -mid_x],
[0, 1, -mid_y],
[0, 0, 0],
[0, 0, 1]], np.float32)
proj3dto2d = np.array([[z_axis, 0, mid_x, 0],
[0, z_axis, mid_y, 0], # defines to centre of rotation
[0, 0, 1, 0]], np.float32)
trans = np.array([[1, 0, 0, x_offset * -1], # Working
[0, 1, 0, y_offset * -1],
[0, 0, 1, 960], # keep as 960
[0, 0, 0, 1]], np.float32)
x = math.degrees(roll_marker) * -1 # forwards and backwards
y = math.degrees(pitch_marker) * -1 # Left and right
z = 0
rx = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]], np.float32) #
ry = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]], np.float32)
rz = np.array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]], np.float32)
ax = float(x * (math.pi / 180.0)) # 0
ay = float(y * (math.pi / 180.0))
az = float(z * (math.pi / 180.0)) # 0
rx[1, 1] = math.cos(ax) # 0
rx[1, 2] = -math.sin(ax) # 0
rx[2, 1] = math.sin(ax) # 0
rx[2, 2] = math.cos(ax) # 0
ry[0, 0] = math.cos(ay)
ry[0, 2] = -math.sin(ay)
ry[2, 0] = math.sin(ay)
ry[2, 2] = math.cos(ay)
rz[0, 0] = math.cos(az) # 0
rz[0, 1] = -math.sin(az) # 0
rz[1, 0] = math.sin(az) # 0
rz[1, 1] = math.cos(az) # 0
# Translation matrix
# r = rx.dot(ry) # if we remove the lines we put r=ry
r = rx.dot(ry) # order may need to be changed
final = proj3dto2d.dot(trans.dot(r.dot(proj2dto3d))) # just rotation
dst = cv2.warpPerspective(img, final, (img.shape[1], img.shape[0]), None, cv2.INTER_LINEAR, cv2.BORDER_CONSTANT, (255, 255, 255))
I have been trying to make a 3d engine with python for some time, and I have gotten pretty far, however I have found a problem in when I try and sort items in a list, the sorting flips when you are close enough to the cube.
main.py:
import os
os.environ["SDL_VIDEO_CENTERED"] = '1'
os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = '1'
import pygame
from pygame import gfxdraw
import math
from matrix import matrix_multiplication
import mesh
from random import randint as random
import time
startTime = time.time()
black, white, blue = (20, 20, 20), (230, 230, 230), (0, 154, 255)
width, height = 700, 700
pygame.init()
pygame.display.set_caption("3D Engine")
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
frames = 60
outline = False
rs, gs, bs = [random(0, 255) for i in range(len(mesh.faces))], [random(0, 255) for i in
range(len(mesh.faces))], [random(0, 255) for i in range(len(mesh.faces))]
angle_x = 0
angle_y = 0
angle_z = 0
pos_x = 0
pos_y = 0
pos_z = 0
cube_position = [width//2, height//2]
scale = 600
speed = 0.001
points = [[[i] for i in j] for j in mesh.verts]
movSpeed = 0.001
font = pygame.font.SysFont("Corbel", 23)
def avarageX(i):
return (new_points[mesh.faces[i][0]][0][0] + new_points[mesh.faces[i][1]][0][0] + new_points[mesh.faces[i][2]][0][0] + new_points[mesh.faces[i][3]][0][0]) / 4
def avarageY(i):
return (new_points[mesh.faces[i][0]][1][0] + new_points[mesh.faces[i][1]][1][0] + new_points[mesh.faces[i][2]][1][0] + new_points[mesh.faces[i][3]][1][0]) / 4
def avarageZ(i):
return (new_points[mesh.faces[i][0]][2][0] + new_points[mesh.faces[i][1]][2][0] + new_points[mesh.faces[i][2]][2][0] + new_points[mesh.faces[i][3]][2][0]) / 4
def distToCam(i):
a = [0, 0, 0]
b = [avarageX(i), avarageY(i), avarageZ(i)]
return math.dist(a, b)
print("It took: {} seconds".format(time.time() - startTime))
run = True
while run:
dt = clock.tick(frames)
fps = clock.get_fps()
screen.fill(white)
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
index = 0
projected_points = [j for j in range(len(points))]
rotation_x = [[1, 0, 0],
[0, math.cos(angle_x), -math.sin(angle_x)],
[0, math.sin(angle_x), math.cos(angle_x)]]
rotation_y = [[math.cos(angle_y), 0, -math.sin(angle_y)],
[0, 1, 0],
[math.sin(angle_y), 0, math.cos(angle_y)]]
rotation_z = [[math.cos(angle_z), -math.sin(angle_z), 0],
[math.sin(angle_z), math.cos(angle_z), 0],
[0, 0, 1]]
new_points = []
for point in points:
rotated_2d = matrix_multiplication(rotation_y, point)
rotated_2d = matrix_multiplication(rotation_x, rotated_2d)
rotated_2d = matrix_multiplication(rotation_z, rotated_2d)
new_point = [[rotated_2d[0][0] + pos_x], [rotated_2d[1][0] + pos_y], [rotated_2d[2][0] - pos_z]]
new_points.append(new_point)
distance = 5
z = 1 / (distance - new_point[2][0])
projection_matrix = [[z, 0, 0],
[0, z, 0]]
projected_2d = matrix_multiplication(projection_matrix, new_point)
x = int(projected_2d[0][0] * scale) + cube_position[0]
y = int(projected_2d[1][0] * scale) + cube_position[1]
projected_points[index] = [x, y]
index += 1
zs = [[distToCam(i), i] for i in range(len(mesh.faces))]
zs.sort(reverse=True)
faces = [[mesh.faces[zs[i][1]], zs[i][1]] for i in range(len(mesh.faces))]
fi = 0
for f in faces:
gfxdraw.filled_polygon(screen, [projected_points[f[0][0]], projected_points[f[0][1]], projected_points[f[0][2]], projected_points[f[0][3]]], (rs[zs[fi][1]], gs[zs[fi][1]], bs[zs[fi][1]]))
gfxdraw.aapolygon(screen, [projected_points[f[0][0]], projected_points[f[0][1]], projected_points[f[0][2]], projected_points[f[0][3]]], (rs[zs[fi][1]], gs[zs[fi][1]], bs[zs[fi][1]]))
fi += 1
angle_x += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * speed * dt
angle_y += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * speed * dt
pos_x += (keys[pygame.K_d] - keys[pygame.K_a]) * movSpeed * dt
pos_z += (keys[pygame.K_w] - keys[pygame.K_s]) * movSpeed * dt
text = font.render(str(round(fps, 1)), False, black)
screen.blit(text, (0, 0))
pygame.display.update()
pygame.quit()
The matrix multiplication
matrix.py:
def matrix_multiplication(a, b):
columns_a = len(a[0])
rows_a = len(a)
columns_b = len(b[0])
rows_b = len(b)
result_matrix = [[j for j in range(columns_b)] for i in range(rows_a)]
if columns_a == rows_b:
for x in range(rows_a):
for y in range(columns_b):
sum = 0
for k in range(columns_a):
sum += a[x][k] * b[k][y]
result_matrix[x][y] = sum
return result_matrix
else:
print("columns of the first matrix must be equal to the rows of the second matrix")
return None
The mesh data.
mesh.py:
verts = [
[1, 1, 1],
[1, 1, -1],
[1, -1, 1],
[1, -1, -1],
[-1, 1, 1],
[-1, 1, -1],
[-1, -1, 1],
[-1, -1, -1]
]
faces = [
[0, 4, 6, 2],
[3, 2, 6, 7],
[7, 6, 4, 5],
[5, 1, 3, 7],
[1, 0, 2, 3],
[5, 4, 0, 1]
]
WARNING: There might be flashing lights on startup
You have to compute the distance of the camera position ([0, 0, distance]) to the points in world space (new_points), instead of the points in model space (points):
def distToCam(i):
a = [0, 0, distance]
b = [sum(new_points[mesh.faces[i][pi]][j][0] for pi in range(4)) / 4 for j in range(3)]
return math.dist(a, b)
I need to solve a problem in which I have spent hours, with the data from my excel sheet I have created a 6x36 '' zeros '' matrix of zeros and a 6x6 '' matrix_tran '' coordinate transformation matrix [image 1].
My problem is that I can't find a way to replace the zeros of the '' zeros '' matrix with the values that the matrix '' matrix_tran '' dictates, and whose location must be in the columns (4,5,6, 7,8,9) that are given by the connection vector (4,5,6,7,8,9) of element 15 of the Excel sheet, that is, the last row of the for loop iteration [image 2].
In summary: Below I show how it fits and how it should look [image 3 and 4 respectively].
I would very much appreciate your help, and excuse my English, but it is not my native language, a big greeting.
import pandas as pd
import numpy as np
ex = pd.ExcelFile('matrix_tr.xlsx')
hoja = ex.parse('Hoja1')
cols = 36
for n in range(0,len(hoja)):
A = hoja['ELEMENT #'][n]
B = hoja['1(i)'][n]
C = hoja['2(i)'][n]
D = hoja['3(i)'][n]
E = hoja['1(j)'][n]
F = hoja['2(j)'][n]
G = hoja['3(j)'][n]
H = hoja['X(i)'][n]
I = hoja['Y(i)'][n]
J = hoja['X(j)'][n]
K = hoja['Y(j)'][n]
L = np.sqrt((J-H)**2+(K-I)**2)
lx = (J-H)/L
ly = (K-I)/L
zeros = np.zeros((6, cols))
counters = hoja.loc[:, ["1(i)", "2(i)", "3(i)", "1(j)", "2(j)", "3(j)"]]
for _, i1, i2, i3, j1, j2, j3 in counters.itertuples():
matrix_tran = np.array([[lx, ly, 0, 0, 0, 0],
[-ly, lx, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, lx, ly, 0],
[0, 0, 0, -ly, lx, 0],
[0, 0, 0, 0, 0, 1]])
zeros[:, [i1 - 1, i2 - 1, i3 - 1, j1 - 1, j2 - 1 , j3 - 1]] = matrix_tran
Try with a transposed zeros matrix
import pandas as pd
import numpy as np
ex = pd.ExcelFile('c:/tmp/SO/matrix_tr.xlsx')
hoja = ex.parse('Hoja1')
counters = hoja.loc[:, ["1(i)", "2(i)", "3(i)", "1(j)", "2(j)", "3(j)"]]
# zeros matrix transposed
cols = 36
zeros_trans = np.zeros((cols,6))
# last row only
for n in range(14,len(hoja)):
Xi = hoja['X(i)'][n]
Yi = hoja['Y(i)'][n]
Xj = hoja['X(j)'][n]
Yj = hoja['Y(j)'][n]
X = Xj-Xi
Y = Yj-Yi
L = np.sqrt(X**2+Y**2)
lx = X/L
ly = Y/L
matrix_tran = np.array([[lx, ly, 0, 0, 0, 0],
[-ly, lx, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, lx, ly, 0],
[0, 0, 0, -ly, lx, 0],
[0, 0, 0, 0, 0, 1]])
i = 0
for r in counters.iloc[n]:
zeros_trans[r-1] = matrix_tran[i]
i += 1
print(np.transpose(zeros_trans))
I have a vector y that either increments or decrements by 1. What I want is to create a another vector y2 that shows when y1 changed direction.
I can't figure out how to do this in numpy.
EDIT updated plot, due to missing comma in y
import matplotlib.pyplot as plt
import numpy as np
EDIT: Fixed missing comma in y
import matplotlib.pyplot as plt
import numpy as np
y = np.array([0,0,1,1,2,2,1,0,-1,-1,0,0,1])
x = np.arange(len(y))
y2 = np.array([0,0,1,0,0,0,-1,0,0,0,1,0,0])
plt.plot(x, y, label='y - Actual')
plt.plot(x, y2, label='y2 - Desired')
plt.legend()
plt.show()
Edit: Now also handles out of spec inputs (increments outside -1, 0, 1).
Here's a slightly faster (for the time being) way (pp is me, D is #Divakar):
# n = 10
# pp 0.02363790 ms
# D 0.03705720 ms
# n = 1000
# pp 0.03609150 ms
# D 0.05877410 ms
# n = 1000000
# pp 22.63471480 ms
# D 36.92147740 ms
Code including benchmarking:
import numpy as np
import types
from timeit import timeit
def setup_data(n, allow_out_of_spec=True):
if allow_out_of_spec:
data = {'y': np.cumsum(np.random.randint(0, 10, (n,))
* np.random.randint(-1, 2, (n,)))}
else:
data = {'y': np.cumsum(np.random.randint(-1, 2, (n,)))}
return data
# mine
def f_pp(y, allow_out_of_spec=True):
if allow_out_of_spec:
d = np.sign(np.diff(y))
else:
d = np.diff(y)
ud = np.flatnonzero(d)
uds = d[ud]
chng = ud[np.r_[True, uds[1:] != uds[:-1]]]
out = np.zeros(len(y), dtype=int)
out[1:][chng] = d[chng]
return out
# #Divakar's
def f_D(y):
s0 = np.flatnonzero(y[1:] > y[:-1])+1
s1 = np.flatnonzero(y[1:] < y[:-1])+1
idx0 = np.searchsorted(s1,s0,'right')
s0c = s0[np.r_[True,idx0[1:] > idx0[:-1]]]
idx1 = np.searchsorted(s0c,s1,'right')
s1c = s1[np.r_[True,idx1[1:] > idx1[:-1]]]
out = np.zeros(len(y),dtype=int)
out[s0c] = 1
out[s1c] = -1
return out
for n in (10, 1000, 1000000):
data = setup_data(n)
ref = np.array(f_pp(**data))
print(f'n = {n}')
for name, func in list(globals().items()):
if not name.startswith('f_') or not isinstance(func, types.FunctionType):
continue
try:
assert np.allclose(ref, func(**data))
print("{:16s}{:16.8f} ms".format(name[2:], timeit(
'f(**data)', globals={'f':func, 'data':data}, number=10)*100))
except:
print("{:16s} apparently failed".format(name[2:]))
Here's one way -
def detect_ups_downs(y):
s0 = np.flatnonzero(y[1:] > y[:-1])+1
s1 = np.flatnonzero(y[1:] < y[:-1])+1
idx0 = np.searchsorted(s1,s0,'right')
s0c = s0[np.r_[True,idx0[1:] > idx0[:-1]]]
idx1 = np.searchsorted(s0c,s1,'right')
s1c = s1[np.r_[True,idx1[1:] > idx1[:-1]]]
out = np.zeros(len(y),dtype=int)
out[s0c] = 1
out[s1c] = -1
return out
Sample run -
In [92]: y = np.array([0,0,1,2,3,4,1,0,-1-1,0,0,1,0,8,8,9,-4,-6,4,-2,2])
In [93]: np.c_[y, detect_ups_downs(y)]
Out[93]:
array([[ 0, 0],
[ 0, 0],
[ 1, 1],
[ 2, 0],
[ 3, 0],
[ 4, 0],
[ 1, -1],
[ 0, 0],
[-2, 0],
[ 0, 1],
[ 0, 0],
[ 1, 0],
[ 0, -1],
[ 8, 1],
[ 8, 0],
[ 9, 0],
[-4, -1],
[-6, 0],
[ 4, 1],
[-2, -1],
[ 2, 1]])
Try taking a derivative:
dy = y[1:] - y[:-1]
Then check if adjacent points have switched derivative signs:
increasing = dy > 0
decreasing = dy < 0
saddle = dy == 0
change_increasing = increasing[1:] and decreasing[:-1]
change_decreasing = decreasing[1:] and increasing[:-1]
Bring all that information together:
changes = np.zeros_like(dy)
changes[0] = (1 * increasing[0]) + (-1 * decreasing[0])
changes[1:][change_increasing] = 1
changes[1:][change_decreasing] = -1
changes[saddle] = 0
print(changes)
So I'm now watching a code related to Markov Chain and the thing is that I don't have no idea how this code works.
transition_probabilities = [
[[0.7, 0.3, 0.0], [1.0, 0.0, 0.0], [0.8, 0.2, 0.0]], # in s0, if action a0 then proba 0.7 to state s0 and 0.3 to state s1, etc.
[[0.0, 1.0, 0.0], None, [0.0, 0.0, 1.0]],
[None, [0.8, 0.1, 0.1], None],
]
rewards = [
[[+10, 0, 0], [0, 0, 0], [0, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, -50]],
[[0, 0, 0], [+40, 0, 0], [0, 0, 0]],
]
possible_actions = [[0, 1, 2], [0, 2], [1]]
def policy_fire(state):
return [0, 2, 1][state]
def policy_random(state):
return rnd.choice(possible_actions[state])
def policy_safe(state):
return [0, 0, 1][state]
class MDPEnvironment(object):
def __init__(self, start_state=0):
self.start_state=start_state
self.reset()
def reset(self):
self.total_rewards = 0
self.state = self.start_state
def step(self, action):
next_state = rnd.choice(range(3), p=transition_probabilities[self.state][action])
reward = rewards[self.state][action][next_state]
self.state = next_state
self.total_rewards += reward
return self.state, reward
def run_episode(policy, n_steps, start_state=0, display=True):
env = MDPEnvironment()
if display:
print("States (+rewards):", end=" ")
for step in range(n_steps):
if display:
if step == 10:
print("...", end=" ")
elif step < 10:
print(env.state, end=" ")
action = policy(env.state)
state, reward = env.step(action)
if display and step < 10:
if reward:
print("({})".format(reward), end=" ")
if display:
print("Total rewards =", env.total_rewards)
return env.total_rewards
for policy in (policy_fire, policy_random, policy_safe):
all_totals = []
print(policy.__name__)
for episode in range(1000):
all_totals.append(run_episode(policy, n_steps=100, display=(episode<5)))
print("Summary: mean={:.1f}, std={:1f}, min={}, max={}".format(np.mean(all_totals), np.std(all_totals), np.min(all_totals), np.max(all_totals)))
print()
In line 16, there is a function returning only index. I've never heard of anything like this. All I know about the index is that it must have a corresponding l_value so that the index can subscribe the element inside an array or whatsoever. So would you guys please tell me what's going on?
Lines 15-16:
def policy_fire(state):
return [0, 2, 1][state]
This function assumes state will be an integer between 0 and 2, and uses that value to index the list [0, 2, 1] and return the resulting value. So e.g. policy_fire(1) will return 2.
This function is called in function run_episode, with env.state as the parameter, where env = MDPEnvironment().