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 @@ + + +
+ +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
+
+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.
+ +
from IPython.display import Video
+Video("./doc/robot-maze.mp4")
+Different Games available here at OpenAI Gym https://gym.openai.com/
+ +import time
+import numpy as np
+
+import gym
+import gym_maze
+Create a 10x10 map
+ +# 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)
+Take a loot at the maze
+ +_ = env.render()
+
Where are we now?
+ +observation = env.reset()
+print("Now we are at:", observation)
+0 - Up
+1 - Down
+2 - Right
+3 - Left
0
+3 2
+ 1
+
+Let's move around
+ +action = 2
+
+observation, reward, done, info = env.step(action)
+print(observation)
+_ = env.render()
+_ = env.step(1)
+_ = env.render()
+Reset to the starting point
+ +_ = env.reset()
+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
+ +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
+
_ = env.reset()
+_ = env.render()
+# 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 = []
+# 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)
+
_ = env.reset()
+_ = env.render()
+for action in solution[0]:
+ _ = env.step(action)
+ time.sleep(0.5)
+ env.render()
+env.close()
+
1. From DFS to BFS (3 LOC)
+2. Implement GBFS (BFS) (2 LOC)
+3. From GBFS (BFS) to GBFS (DFS) (2 LOC)
+
+| + | maze1 | +maze2 | +maze3 | +
|---|---|---|---|
| DFS | +11 | +194 | +17 | +
| BFS | ++ | + | + |
| GBFS (BFS) | ++ | + | + |
| GBFS (DFS) | ++ | + | + |
| A* | +- | +- | +- | +
+A* Search
+ +
+