diff --git a/doc/doc-compose.yml b/doc/doc-compose.yml new file mode 100644 index 0000000..7f6bd97 --- /dev/null +++ b/doc/doc-compose.yml @@ -0,0 +1,26 @@ +version: "3.3" + +services: + nginx: + image: nginx:stable-alpine + volumes: + - ./doc:/usr/share/nginx/html + - ./nginx-doc.conf:/etc/nginx/conf.d/default.conf + deploy: + labels: + - "traefik.enable=true" + - "traefik.http.routers.doc.rule=Host(`doc.trustai.uk`)" + - "traefik.http.routers.doc.entrypoints=web" + - "traefik.http.services.doc.loadbalancer.server.port=80" + # TLS + - "traefik.http.routers.docs.rule=Host(`doc.trustai.uk`)" + - "traefik.http.routers.docs.entrypoints=websecure" + - "traefik.http.routers.docs.tls.certresolver=myhttpchallenge" + # Redirect + - "traefik.http.routers.doc.middlewares=https_redirect" + - "traefik.http.middlewares.https_redirect.redirectscheme.scheme=https" + networks: + - traefik-public +networks: + traefik-public: + external: true diff --git a/doc/doc/workshop-1/doc/a_star.png b/doc/doc/workshop-1/doc/a_star.png new file mode 100644 index 0000000..0553258 Binary files /dev/null and b/doc/doc/workshop-1/doc/a_star.png differ diff --git a/doc/doc/workshop-1/doc/maze.png b/doc/doc/workshop-1/doc/maze.png new file mode 100644 index 0000000..defd6fe Binary files /dev/null and b/doc/doc/workshop-1/doc/maze.png differ diff --git a/doc/doc/workshop-1/doc/maze25d.png b/doc/doc/workshop-1/doc/maze25d.png new file mode 100644 index 0000000..2eaacbb Binary files /dev/null and b/doc/doc/workshop-1/doc/maze25d.png differ diff --git a/doc/doc/workshop-1/doc/maze2d-large.png b/doc/doc/workshop-1/doc/maze2d-large.png new file mode 100644 index 0000000..46e26a6 Binary files /dev/null and b/doc/doc/workshop-1/doc/maze2d-large.png differ diff --git a/doc/doc/workshop-1/doc/maze2d-small.png b/doc/doc/workshop-1/doc/maze2d-small.png new file mode 100644 index 0000000..1e6d2a1 Binary files /dev/null and b/doc/doc/workshop-1/doc/maze2d-small.png differ diff --git a/doc/doc/workshop-1/doc/maze3d.png b/doc/doc/workshop-1/doc/maze3d.png new file mode 100644 index 0000000..db101c4 Binary files /dev/null and b/doc/doc/workshop-1/doc/maze3d.png differ diff --git a/doc/doc/workshop-1/doc/neighbor.png b/doc/doc/workshop-1/doc/neighbor.png new file mode 100644 index 0000000..53f8bc6 Binary files /dev/null and b/doc/doc/workshop-1/doc/neighbor.png differ diff --git a/doc/doc/workshop-1/doc/robot-maze.mp4 b/doc/doc/workshop-1/doc/robot-maze.mp4 new file mode 100644 index 0000000..0ffb963 Binary files /dev/null and b/doc/doc/workshop-1/doc/robot-maze.mp4 differ diff --git a/doc/doc/workshop-1/doc/search.gif b/doc/doc/workshop-1/doc/search.gif new file mode 100644 index 0000000..35011fa Binary files /dev/null and b/doc/doc/workshop-1/doc/search.gif differ diff --git a/doc/doc/workshop-1/doc/solution.gif b/doc/doc/workshop-1/doc/solution.gif new file mode 100644 index 0000000..4bc03c6 Binary files /dev/null and b/doc/doc/workshop-1/doc/solution.gif differ diff --git a/doc/doc/workshop-1/workshop-1.html b/doc/doc/workshop-1/workshop-1.html new file mode 100644 index 0000000..9ae9ca8 --- /dev/null +++ b/doc/doc/workshop-1/workshop-1.html @@ -0,0 +1,13933 @@ + + + + +Workshop - 1 (DFS BFS) + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+

Prerequisites

+
+
+
+
+
+
+ + +
+
+
+
+
+
+

Environment Set Up

+ +
+
+
+
+
+
+ +
$ conda create -n maze python=3.8
+$ conda activate maze
+
+$ pip install gym numpy jupyter
+
+$ cd gym-maze
+$ python setup.py install
+$ cd ..
+$ jupyter notebook
+ +
+
+
+
+
+
+

Why do we need BFS DFS A*?

+
+
+
+
+
+
+
+
+
+

Solving a small maze is trivial.

+ +
+
+
+
+
+
+

+ +
+
+
+
+
+
+

How about this one?

+ +
+
+
+
+
+
+

+ +
+
+
+
+
+ +
+
+
+
+
+

For Local Search, we do not have access to the whole map. Only surrounding info available.

+ +
+
+
+
+
+
+

+ +
+
+
+
+
+
+
+
+
+

We can not see through walls. Only to decide which direction to go.

+ +
+
+
+
+
+
+

+ +
+
+
+
+
+
+

Real-World Applications

+
+
+
+
+
+
In [1]:
+
+
+
from IPython.display import Video
+
+ +
+
+
+ +
+
+
+
In [2]:
+
+
+
Video("./doc/robot-maze.mp4")
+
+ +
+
+
+ +
+
+ + +
+ +
Out[2]:
+ + + +
+ +
+ +
+ +
+
+ +
+
+
+
+

Let's build this robot

+
+
+
+
+
+
+

Different Games available here at OpenAI Gym https://gym.openai.com/

+ +
+
+
+
+
+
In [3]:
+
+
+
import time
+import numpy as np
+
+import gym
+import gym_maze
+
+ +
+
+
+ +
+
+
+
+

Create a 10x10 map

+ +
+
+
+
+
+
In [4]:
+
+
+
# env = gym.make("maze-sample-3x3-v0"); goal = (2, 2)
+# env = gym.make("maze-sample-5x5-v0"); goal = (4, 4)
+env = gym.make("maze-sample-10x10-v0"); goal = (9, 9)
+# env = gym.make("maze-sample-100x100-v0"); goal = (99, 99)
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
pygame 1.9.6
+Hello from the pygame community. https://www.pygame.org/contribute.html
+
+
+
+ +
+
+ +
+
+
+
+

Take a loot at the maze

+ +
+
+
+
+
+
In [5]:
+
+
+
_ = env.render()
+
+ +
+
+
+ +
+
+
+
+

+ +
+
+
+
+
+
+

Where are we now?

+ +
+
+
+
+
+
In [6]:
+
+
+
observation = env.reset()
+print("Now we are at:", observation)
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
Now we are at: [0. 0.]
+
+
+
+ +
+
+ +
+
+
+
+

0 - Up
+1 - Down
+2 - Right
+3 - Left

+ +
+
+
+
+
+
+ +
   0
+3     2
+   1
+ +
+
+
+
+
+
+

Let's move around

+ +
+
+
+
+
+
In [7]:
+
+
+
action = 2
+
+observation, reward, done, info = env.step(action)
+print(observation)
+_ = env.render()
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
[1 0]
+
+
+
+ +
+
+ +
+
+
+
In [8]:
+
+
+
_ = env.step(1)
+_ = env.render()
+
+ +
+
+
+ +
+
+
+
+

Reset to the starting point

+ +
+
+
+
+
+
In [9]:
+
+
+
_ = env.reset()
+
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+
+
In [10]:
+
+
+
class Node():
+    def __init__(self, state, parent, action, done):
+        self.state = state
+        self.parent = parent
+        self.action = action
+        self.done = False
+
+
+class StackFrontier():
+    def __init__(self):
+        self.frontier = []
+
+    def add(self, node):
+        self.frontier.append(node)
+
+    def contains_state(self, state):
+        return any(node.state == state for node in self.frontier)
+
+    def empty(self):
+        return len(self.frontier) == 0
+
+    def remove(self):
+        if self.empty():
+            raise Exception("empty frontier")
+        else:
+            node = self.frontier[-1]
+            self.frontier = self.frontier[:-1]
+            return node
+
+ +
+
+
+ +
+
+
+
+ +
   0
+3     2
+   1
+ +
+
+
+
+
+
+

Find neighnors

+ +
+
+
+
+
+
In [11]:
+
+
+
reverse_action = [1, 0, 3, 2]
+
+def neighbors(state):
+    candidates = [0, 1, 2, 3]
+    result = []
+
+    for action in candidates:
+        # Take each possible action
+        observation, _, done, _ = env.step(action)
+        env.render()
+        # If the position remains the same, it means there is a wall.
+        # The action is valid only when the position changes. (no wall)
+        if ( not (observation == np.array(state)).all() ):
+            result.append((action, tuple(observation), done))
+            # Go back first, and try next action
+            _, _, _, _ = env.step(reverse_action[action])
+            env.render()
+
+    return result
+
+ +
+
+
+ +
+
+
+
+

+ +
+
+
+
+
+
+

First, reset the maze

+
+
+
+
+
+
In [12]:
+
+
+
_ = env.reset()
+_ = env.render()
+
+ +
+
+
+ +
+
+
+
+

Time to Explore

+
+
+
+
+
+
In [13]:
+
+
+
# Keep track of number of states explored
+num_explored = 0
+
+# Initialize frontier to just the starting position
+start = Node(state=env.reset(), parent=None, action=0, done=False)
+frontier = StackFrontier()
+frontier.add(start)
+
+# Initialize an empty explored set
+explored = set()
+solution = None
+
+action_stack = []
+
+ +
+
+
+ +
+
+
+
In [14]:
+
+
+
# Keep looping until solution found
+while True:
+
+    # If nothing left in frontier, then no path
+    if frontier.empty():
+        raise Exception("no solution")
+
+    # Choose a node from the frontier
+    # 0 - Up  
+    # 1 - Down  
+    # 2 - Right  
+    # 3 - Left 
+    node = frontier.remove()
+
+    _, _, done, _ = env.step(node.action)
+    action_stack.append(node.action)
+    env.render()
+    time.sleep(0.1)
+    num_explored += 1
+
+    # If node is the goal, then we have a solution
+    if done:
+        actions = []
+        cells = []
+        while node.parent is not None:
+            actions.append(node.action)
+            cells.append(node.state)
+            node = node.parent
+        actions.reverse()
+        cells.reverse()
+        solution = (actions, cells)
+        break
+
+    # Mark node as explored
+    explored.add( tuple(node.state) )
+
+    # Add neighbors to frontier
+    i = 0
+    for action, state, done in neighbors(node.state):
+        if (not frontier.contains_state(state)) and (state not in explored):
+            i = i + 1
+            child = Node(state=state, parent=node, action=action, done=done)
+            frontier.add(child)
+
+    # No available neighbors, go back
+    if(i == 0):
+        while (not (np.array(frontier.frontier[-1].parent.state) == np.array(node.state)).all()):
+            observation, _, done, _ = env.step(reverse_action[action_stack.pop()])
+            env.render()
+            node.state =  tuple(observation) 
+
+ +
+
+
+ +
+
+
+
+

+ +
+
+
+
+
+
+

Reset the maze

+
+
+
+
+
+
In [15]:
+
+
+
_ = env.reset()
+_ = env.render()
+
+ +
+
+
+ +
+
+
+
+

Run solution

+
+
+
+
+
+
In [16]:
+
+
+
for action in solution[0]:
+    _ = env.step(action)
+    time.sleep(0.5)
+    env.render()
+
+ +
+
+
+ +
+
+
+
In [17]:
+
+
+
env.close()
+
+ +
+
+
+ +
+
+
+
+

+ +
+
+
+
+
+
+

Assignment

+
+
+
+
+
+
+ +
1. From DFS to BFS                   (3 LOC)
+2. Implement GBFS (BFS)              (2 LOC)
+3. From GBFS (BFS) to GBFS (DFS)     (2 LOC)
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
maze1maze2maze3
DFS1119417
BFS
GBFS (BFS)
GBFS (DFS)
A*---
+ +
+
+
+
+
+
In [ ]:
+
+
+
 
+
+ +
+
+
+ +
+
+
+
+

Congradulations, See you next week

+
+
+
+
+
+
+

A* Search

+ +
+
+
+
+
+
+

+ +
+
+
+ +
+
+
In [ ]:
+
+
+
 
+
+ +
+
+
+ +
+
+
+ + + + + + diff --git a/doc/nginx-doc.conf b/doc/nginx-doc.conf new file mode 100644 index 0000000..d5797ef --- /dev/null +++ b/doc/nginx-doc.conf @@ -0,0 +1,13 @@ +server{ + listen 80; + server_name _; + real_ip_header X-Forwarded-For; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + root /usr/share/nginx/html; + index index.html; + autoindex on; +} +