[workshop] Add notebook

This commit is contained in:
Wu Han 2021-01-06 19:26:53 +00:00
parent 38dce8dc73
commit 4d2d53da56
35 changed files with 9599 additions and 4 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

122
Workshop - 3 (Game).ipynb Normal file
View File

@ -0,0 +1,122 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create a terminal here"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/terminal.png\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Change working directory"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```bash\n",
"$ cd Workshop\\ -\\ 3\\ \\(Game\\)/\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/pwd.png\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Run the game"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```bash\n",
"$ python3 minimax.py\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/minimax.png\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"```bash\n",
"$ python3 ab-pruning.py\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src=\"images/ab-pruning.png\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Reading Materials"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"https://stackabuse.com/minimax-and-alpha-beta-pruning-in-python/"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,191 @@
# We'll use the time module to measure the time of evaluating
# game tree in every move. It's a nice way to show the
# distinction between the basic Minimax and Minimax with
# alpha-beta pruning :)
import time
class Game:
def __init__(self):
self.initialize_game()
def initialize_game(self):
self.current_state = [['.','.','.'],
['.','.','.'],
['.','.','.']]
# Player X always plays first
self.player_turn = 'X'
def draw_board(self):
for i in range(0, 3):
for j in range(0, 3):
print('{}|'.format(self.current_state[i][j]), end=" ")
print()
print()
# Determines if the made move is a legal move
def is_valid(self, px, py):
if px < 0 or px > 2 or py < 0 or py > 2:
return False
elif self.current_state[px][py] != '.':
return False
else:
return True
# Checks if the game has ended and returns the winner in each case
def is_end(self):
# Vertical win
for i in range(0, 3):
if (self.current_state[0][i] != '.' and
self.current_state[0][i] == self.current_state[1][i] and
self.current_state[1][i] == self.current_state[2][i]):
return self.current_state[0][i]
# Horizontal win
for i in range(0, 3):
if (self.current_state[i] == ['X', 'X', 'X']):
return 'X'
elif (self.current_state[i] == ['O', 'O', 'O']):
return 'O'
# Main diagonal win
if (self.current_state[0][0] != '.' and
self.current_state[0][0] == self.current_state[1][1] and
self.current_state[0][0] == self.current_state[2][2]):
return self.current_state[0][0]
# Second diagonal win
if (self.current_state[0][2] != '.' and
self.current_state[0][2] == self.current_state[1][1] and
self.current_state[0][2] == self.current_state[2][0]):
return self.current_state[0][2]
# Is whole board full?
for i in range(0, 3):
for j in range(0, 3):
# There's an empty field, we continue the game
if (self.current_state[i][j] == '.'):
return None
# It's a tie!
return '.'
def max_alpha_beta(self, alpha, beta):
maxv = -2
px = None
py = None
result = self.is_end()
if result == 'X':
return (-1, 0, 0)
elif result == 'O':
return (1, 0, 0)
elif result == '.':
return (0, 0, 0)
for i in range(0, 3):
for j in range(0, 3):
if self.current_state[i][j] == '.':
self.current_state[i][j] = 'O'
(m, min_i, in_j) = self.min_alpha_beta(alpha, beta)
if m > maxv:
maxv = m
px = i
py = j
self.current_state[i][j] = '.'
# Next two ifs in Max and Min are the only difference between regular algorithm and minimax
if maxv >= beta:
return (maxv, px, py)
if maxv > alpha:
alpha = maxv
return (maxv, px, py)
def min_alpha_beta(self, alpha, beta):
minv = 2
qx = None
qy = None
result = self.is_end()
if result == 'X':
return (-1, 0, 0)
elif result == 'O':
return (1, 0, 0)
elif result == '.':
return (0, 0, 0)
for i in range(0, 3):
for j in range(0, 3):
if self.current_state[i][j] == '.':
self.current_state[i][j] = 'X'
(m, max_i, max_j) = self.max_alpha_beta(alpha, beta)
if m < minv:
minv = m
qx = i
qy = j
self.current_state[i][j] = '.'
if minv <= alpha:
return (minv, qx, qy)
if minv < beta:
beta = minv
return (minv, qx, qy)
def play_alpha_beta(self):
while True:
self.draw_board()
self.result = self.is_end()
if self.result != None:
if self.result == 'X':
print('The winner is X!')
elif self.result == 'O':
print('The winner is O!')
elif self.result == '.':
print("It's a tie!")
self.initialize_game()
return
if self.player_turn == 'X':
while True:
start = time.time()
(m, qx, qy) = self.min_alpha_beta(-2, 2)
end = time.time()
print('Evaluation time: {}s'.format(round(end - start, 7)))
print('Recommended move: X = {}, Y = {}'.format(qx, qy))
px = int(input('Insert the X coordinate: '))
py = int(input('Insert the Y coordinate: '))
qx = px
qy = py
if self.is_valid(px, py):
self.current_state[px][py] = 'X'
self.player_turn = 'O'
break
else:
print('The move is not valid! Try again.')
else:
(m, px, py) = self.max_alpha_beta(-2, 2)
self.current_state[px][py] = 'O'
self.player_turn = 'X'
def main():
g = Game()
g.play_alpha_beta()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,204 @@
# We'll use the time module to measure the time of evaluating
# game tree in every move. It's a nice way to show the
# distinction between the basic Minimax and Minimax with
# alpha-beta pruning :)
import time
class Game:
def __init__(self):
self.initialize_game()
def initialize_game(self):
self.current_state = [['.','.','.'],
['.','.','.'],
['.','.','.']]
# Player X always plays first
self.player_turn = 'X'
def draw_board(self):
for i in range(0, 3):
for j in range(0, 3):
print('{}|'.format(self.current_state[i][j]), end=" ")
print()
print()
# Determines if the made move is a legal move
def is_valid(self, px, py):
if px < 0 or px > 2 or py < 0 or py > 2:
return False
elif self.current_state[px][py] != '.':
return False
else:
return True
# Checks if the game has ended and returns the winner in each case
def is_end(self):
# Vertical win
for i in range(0, 3):
if (self.current_state[0][i] != '.' and
self.current_state[0][i] == self.current_state[1][i] and
self.current_state[1][i] == self.current_state[2][i]):
return self.current_state[0][i]
# Horizontal win
for i in range(0, 3):
if (self.current_state[i] == ['X', 'X', 'X']):
return 'X'
elif (self.current_state[i] == ['O', 'O', 'O']):
return 'O'
# Main diagonal win
if (self.current_state[0][0] != '.' and
self.current_state[0][0] == self.current_state[1][1] and
self.current_state[0][0] == self.current_state[2][2]):
return self.current_state[0][0]
# Second diagonal win
if (self.current_state[0][2] != '.' and
self.current_state[0][2] == self.current_state[1][1] and
self.current_state[0][2] == self.current_state[2][0]):
return self.current_state[0][2]
# Is whole board full?
for i in range(0, 3):
for j in range(0, 3):
# There's an empty field, we continue the game
if (self.current_state[i][j] == '.'):
return None
# It's a tie!
return '.'
# Player 'O' is max, in this case AI
def max(self):
# Possible values for maxv are:
# -1 - loss
# 0 - a tie
# 1 - win
# We're initially setting it to -2 as worse than the worst case:
maxv = -2
px = None
py = None
result = self.is_end()
# If the game came to an end, the function needs to return
# the evaluation function of the end. That can be:
# -1 - loss
# 0 - a tie
# 1 - win
if result == 'X':
return (-1, 0, 0)
elif result == 'O':
return (1, 0, 0)
elif result == '.':
return (0, 0, 0)
for i in range(0, 3):
for j in range(0, 3):
if self.current_state[i][j] == '.':
# On the empty field player 'O' makes a move and calls Min
# That's one branch of the game tree.
self.current_state[i][j] = 'O'
(m, min_i, min_j) = self.min()
# Fixing the maxv value if needed
if m > maxv:
maxv = m
px = i
py = j
# Setting back the field to empty
self.current_state[i][j] = '.'
return (maxv, px, py)
# Player 'X' is min, in this case human
def min(self):
# Possible values for minv are:
# -1 - win
# 0 - a tie
# 1 - loss
# We're initially setting it to 2 as worse than the worst case:
minv = 2
qx = None
qy = None
result = self.is_end()
if result == 'X':
return (-1, 0, 0)
elif result == 'O':
return (1, 0, 0)
elif result == '.':
return (0, 0, 0)
for i in range(0, 3):
for j in range(0, 3):
if self.current_state[i][j] == '.':
self.current_state[i][j] = 'X'
(m, max_i, max_j) = self.max()
if m < minv:
minv = m
qx = i
qy = j
self.current_state[i][j] = '.'
return (minv, qx, qy)
def play(self):
while True:
self.draw_board()
self.result = self.is_end()
# Printing the appropriate message if the game has ended
if self.result != None:
if self.result == 'X':
print('The winner is X!')
elif self.result == 'O':
print('The winner is O!')
elif self.result == '.':
print("It's a tie!")
self.initialize_game()
return
# If it's player's turn
if self.player_turn == 'X':
while True:
start = time.time()
(m, qx, qy) = self.min()
end = time.time()
print('Evaluation time: {}s'.format(round(end - start, 7)))
print('Recommended move: X = {}, Y = {}'.format(qx, qy))
px = int(input('Insert the X coordinate: '))
py = int(input('Insert the Y coordinate: '))
(qx, qy) = (px, py)
if self.is_valid(px, py):
self.current_state[px][py] = 'X'
self.player_turn = 'O'
break
else:
print('The move is not valid! Try again.')
# If it's AI's turn
else:
(m, px, py) = self.max()
self.current_state[px][py] = 'O'
self.player_turn = 'X'
def main():
g = Game()
g.play()
if __name__ == "__main__":
main()

252
Workshop - 3 (LP).ipynb Normal file
View File

@ -0,0 +1,252 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Make sure you run this at the begining**"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"np.set_printoptions(suppress=True)\n",
"from scipy.optimize import linprog"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Feasible Example"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\\begin{align}\n",
"\\max f=4x_1+x_2 \\\\\n",
"\\text{s.t.} -x_1 + 2x_2 &\\leq 4 \\\\\n",
"2x_1 + 3x_2 &\\leq 12 \\\\\n",
"x_1 - x_2 &\\leq 3 \\\\\n",
"\\text{and } x_1, x_2 \\geq 0\n",
"\\end{align}"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"c = [-4, -1, 0, 0, 0]\n",
"A = [[-1, 2, 0, 0, 0], [2, 3, 0, 0, 0], [1, -1, 0, 0, 0]]\n",
"b = [4, 12, 3]\n",
"\n",
"x0_bounds = (0, None)\n",
"x1_bounds = (0, None)\n",
"x2_bounds = (None, None)\n",
"x3_bounds = (None, None)\n",
"x4_bounds = (None, None)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" con: array([], dtype=float64)\n",
" fun: -17.999999976555795\n",
" message: 'Optimization terminated successfully.'\n",
" nit: 4\n",
" slack: array([5.8 , 0.00000002, 0. ])\n",
" status: 0\n",
" success: True\n",
" x: array([4.19999999, 1.2 , 0. , 0. , 0. ])\n"
]
}
],
"source": [
"res = linprog(c, A_ub=A, b_ub=b, bounds=[x0_bounds, x1_bounds, x2_bounds, x3_bounds, x4_bounds])\n",
"\n",
"print(res)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Infeasible Example"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\\begin{align}\n",
"\\min f = x_1 - 2x_2 + 3x_3 \\\\\n",
"s.t. -2x_1 + x_2 + 3x_3 & = 2 \\\\\n",
"3x_1 + 3x_2 + 4x_3 & = 1 \\\\\n",
"\\end{align}"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"c = [-1, 2, -3]\n",
"A = [[-2, 1, 3], [3, 3, 4]]\n",
"b = [2, 1]\n",
"\n",
"x0_bounds = (0, None)\n",
"x1_bounds = (0, None)\n",
"x2_bounds = (0, None)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" con: array([ 0. , -4.56053464])\n",
" fun: -0.6099904044751114\n",
" message: 'The algorithm terminated successfully and determined that the problem is infeasible.'\n",
" nit: 4\n",
" slack: array([], dtype=float64)\n",
" status: 2\n",
" success: False\n",
" x: array([0.2893146 , 0.75265113, 0.60865936])\n"
]
}
],
"source": [
"res = linprog(c, A_eq=A, b_eq=b, bounds=[x0_bounds, x1_bounds, x2_bounds,])\n",
"\n",
"print(res)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1><font color='red'>Assignment</font></h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\\begin{align}\n",
"\\min f = 3x_1 - x_2 \\\\\n",
"s.t. 2x_1 + x_2 & \\geq 2 \\\\\n",
"x_1 + 3x_2 & \\leq 3 \\\\\n",
"x_2 & \\leq 4 \\\\\n",
"\\text{and } x_1, x_2 \\geq 0\n",
"\\end{align}"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"c = [-3, 1]\n",
"A = [[-2, -1], [1, 3], [0, 1]]\n",
"b = [-2, 3, 4]\n",
"\n",
"x0_bounds = (0, None)\n",
"x1_bounds = (0, None)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" con: array([], dtype=float64)\n",
" fun: -8.999999998556428\n",
" message: 'Optimization terminated successfully.'\n",
" nit: 4\n",
" slack: array([4., 0., 4.])\n",
" status: 0\n",
" success: True\n",
" x: array([3., 0.])\n"
]
}
],
"source": [
"res = linprog(c, A_ub=A, b_ub=b, bounds=[x0_bounds, x1_bounds])\n",
"\n",
"print(res)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.8.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

1026
Workshop - 4 (TSP SA).ipynb Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

1317
Workshop - 6 (GA, SOM).ipynb Normal file

File diff suppressed because one or more lines are too long

BIN
images/ab-pruning.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
images/minimax.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
images/pwd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
images/solutions.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
images/terminal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
images/tsp.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

View File

@ -1,3 +1,6 @@
## Build Image
docker build -t com2014-tsp .
## Windows

View File

@ -35,13 +35,13 @@ def TSP(tsp_file, model):
coords = load_data(tsp_file)
# Set timeout
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(60)
# signal.signal(signal.SIGALRM, timeout_handler)
# signal.alarm(60)
# Try your algorithm
try:
model.init(coords)
best_solution, fitness_list = model.fit(max_it=100000)
best_solution, fitness_list = model.fit(max_it=10000)
except Exception as exc:
if(str(exc) == "Timeout"):
log("Timeout -3")

View File

@ -72,7 +72,7 @@ class SimAnneal(Model):
self.log("Starting annealing.")
while self.T >= self.stopping_temperature and self.iteration < max_it:
candidate = list(self.cur_solution)
l = random.randint(2, self.N - 1)
l = random.randint(1, self.N - 1)
i = random.randint(0, self.N - l)
candidate[i : (i + l)] = reversed(candidate[i : (i + l)])
self.accept(candidate)

8
template/output/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# .gitignore sample
###################
# Ignore all files in this dir...
*
# ... except for this one.
!.gitignore

View File

@ -0,0 +1,21 @@
def log(msg):
print('[*] {msg}'.format(msg=msg))
def load_data(file):
coords = []
with open(file, "r") as infile:
line = infile.readline()
# Skip instance header
while "NODE_COORD_SECTION" not in line:
line = infile.readline()
for line in infile.readlines():
line = line.replace("\n", "")
if line and 'EOF' not in line:
line = [float(x) for x in line.lstrip().split(" ", 1)[1].split(" ") if x]
coords.append(line)
return coords
def timeout_handler(signum, frame):
print("Timeout")
raise Exception("Timeout")

139
template/utils/tsp.py Normal file
View File

@ -0,0 +1,139 @@
import os
import signal
import json
import math
import timeit
from utils.load_data import load_data
from utils.load_data import log
def timeout_handler(signum, frame):
raise Exception("Timeout")
def dist(node_0, node_1, coords):
"""
Euclidean distance between two nodes.
"""
coord_0, coord_1 = coords[node_0], coords[node_1]
return math.sqrt((coord_0[0] - coord_1[0]) ** 2 + (coord_0[1] - coord_1[1]) ** 2)
def fitness(solution, coords):
N = len(coords)
cur_fit = 0
for i in range(len(solution)):
cur_fit += dist(solution[i % N], solution[(i + 1) % N], coords)
return cur_fit
def TSP_Bench(tsp_file, model, *args, max_it=1000, timeout=60):
start = timeit.default_timer()
# Model Running
best_solution, fitness_list = TSP(tsp_file, model, *args, max_it=max_it,timeout=timeout)
# Model End
stop = timeit.default_timer()
print('[*] Running for: {time:.2f} seconds'.format(time=(stop - start)))
print()
return best_solution, fitness_list, (stop - start)
def TSP_Bench_ALL(tsp_file_path, model, *args, max_it=1000, timeout=60):
best_solutions = []
fitness_lists = []
times = []
for root, _, files in os.walk(tsp_file_path):
if(files):
for f in files:
# Get input file name
tsp_file = str(root) + '/' + str(f)
log(tsp_file)
# Run TSP
best_solution, fitness_list, time = TSP_Bench(tsp_file, model, *args, max_it=max_it,timeout=timeout)
best_solutions.append(best_solution)
fitness_lists.append(fitness_lists)
times.append(time)
return best_solutions, fitness_lists, times
def TSP(tsp_file, model, *args, max_it=1000, timeout=60):
best_solution = []
fitness_list = []
nodes = load_data(tsp_file)
# Set timeout
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(timeout)
if not os.path.exists('output'):
os.makedirs('output')
# Try your algorithm
try:
model.init(nodes, *args)
best_solution, fitness_list = model.fit(max_it)
except Exception as exc:
if(str(exc) == "Timeout"):
log("Timeout -3")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-3")
best_solution = [-1] * len(nodes)
else:
print(exc)
log("Unkown -4")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-4")
signal.alarm(0)
# Collect results
if(len(fitness_list) > 0):
log("[Node] " + str(len(best_solution)) + ", [Best] " + str(fitness_list[fitness_list.index(min(fitness_list))]))
if (len(best_solution) == 0):
log("No Answer -1")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-1")
elif (len(best_solution) != len(nodes)):
log("Invalid -2")
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write("-2")
else:
# log("Writing the best solution to file" )
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.txt', "w") as outfile:
outfile.write(str(model.fitness(best_solution)))
outfile.write("\n")
outfile.write(", ".join(str(item) for item in best_solution))
# Write to JSON
data = {}
data['nodes'] = []
for i in range(len(nodes)):
data['nodes'].append({
'title': str(i),
'id': i,
'x': int(nodes[i][0]),
'y': int(nodes[i][1])
})
data['edges'] = []
for i in range(len(best_solution)):
if i == len(best_solution)-1:
data['edges'].append({
'source': best_solution[i],
'target': best_solution[0]
})
else:
data['edges'].append({
'source': best_solution[i],
'target': best_solution[i+1]
})
with open('output/' + os.path.splitext(os.path.basename(tsp_file))[0] + '.json', 'w') as outfile:
json.dump(data, outfile)
return best_solution, fitness_list