Skip to content

Commit

Permalink
Updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
TheoLvs committed Sep 17, 2021
1 parent cc04ea5 commit 088f2c1
Show file tree
Hide file tree
Showing 25 changed files with 1,826 additions and 43 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
## Description
**Westworld** is a multi-agent simulation library, its goal to simulate and optimize systems and environments with multiple agents interacting. Its inspiration is drawn from Unity software and [Unity ML Agents](https://github.com/Unity-Technologies/ml-agents), adapted in Python.

The goal is to be able to simulate environments in logistics, retails, epidemiology, providing pre-coded spatial environments and communication between agents. Optimization can be included using heuristics as well as Reinforcement Learning.
The goal is to be able to simulate environments in logistics, retail, epidemiology, providing pre-coded spatial environments and communication between agents. Optimization can be included using heuristics as well as Reinforcement Learning.

!!! warning "Experimental"
This library is extremely experimental, under active development and alpha-release
Expand Down Expand Up @@ -59,3 +59,6 @@ poetry run python
## Contributors
- [Théo Alves Da Costa](mailto:[email protected])

## Javascript version
A javascript version is being developed at https://github.com/TheoLvs/westworldjs

58 changes: 55 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## Description
**Westworld** is a multi-agent simulation library, its goal to simulate and optimize systems and environments with multiple agents interacting. Its inspiration is drawn from Unity software and [Unity ML Agents](https://github.com/Unity-Technologies/ml-agents), adapted in Python.

The goal is to be able to simulate environments in logistics, retails, epidemiology, providing pre-coded spatial environments and communication between agents. Optimization can be included using heuristics as well as Reinforcement Learning.
The goal is to be able to simulate environments in logistics, retail, epidemiology, providing pre-coded spatial environments and communication between agents. Optimization can be included using heuristics as well as Reinforcement Learning.

!!! warning "Experimental"
This library is extremely experimental, under active development and alpha-release
Expand All @@ -15,6 +15,58 @@ The goal is to be able to simulate environments in logistics, retails, epidemiol
*The name is of course inspired by the TV series Westworld, which is actually a gigantic multi-agent simulation system.*


## Quickstart
Let's model an ecosystem of rabbits looking and competing for food

![](./tutorials/img/Quickstart_1631837803.gif)

```python
from westworld.environment import GridEnvironment
from westworld.agents import BaseAgent
from westworld.objects import BaseCollectible
from westworld.simulation import Simulation
from westworld.colors import *

class Food(BaseCollectible):
pass

class Rabbit(BaseAgent):

def __init__(self,x,y,curiosity = 5):
super().__init__(x,y,color = (229, 229, 229),curiosity = curiosity)

def step(self):

# Find closest food
targets = self.find_closest(name = "Food",k = 1)

# If there is still food, move towards the food
if len(targets) > 0:

target = targets[0]

# Use naive pathfinding for faster computation as there is no obstacle
self.move_towards(obj = target,naive = True)

# Otherwise just wandering
# Changing direction every n steps where n = curiosity
else:
self.wander()

food_spawner = lambda x,y : Food(x,y,color = (220,150,50),img_asset = "ball")
rabbit_spawner = lambda x,y : Rabbit(x,y,curiosity = 5)

# Setup environment
env = GridEnvironment(20,10,20,show_grid = True,background_color=(102, 178, 102),grid_color=(127, 191, 127),toroidal=True)
env.spawn(rabbit_spawner,3)
env.spawn(food_spawner,20)
env.render()

# Make simulation
sim = Simulation(env,fps = 10,name="Quickstart")
_,_ = sim.run_episode(n_steps = 50,save = True,replay = True,save_format="gif",)
```

## Features
### Current features
- Easy creation of Grid and non-grid environments
Expand Down Expand Up @@ -59,6 +111,6 @@ poetry run python
- [Théo Alves Da Costa](mailto:[email protected])




## Javascript version
A javascript version is being developed at https://github.com/TheoLvs/westworldjs

Binary file added docs/tutorials/img/Quickstart_1631837803.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/tutorials/img/RandomWalk_1631836560.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/tutorials/img/RandomWalk_1631837025.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/tutorials/img/RandomWalk_1631837258.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added docs/tutorials/maze.md
Empty file.
70 changes: 70 additions & 0 deletions docs/tutorials/movements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Movements

For each step in the simulation, the environment will calculate what happens to every non-stationary objects binded to it.
In particular, the agents who will probably move between t and t+1.

If you can subclass the ``step()`` function for any custom movements. There are already many pre-coded functions to make your agent move.

We will need the basic westworld imports for this tutorial
```python
from westworld.environment import GridEnvironment
from westworld.agents import BaseAgent
from westworld.simulation import Simulation
from westworld.colors import BLUE,GREEN,RED
```

## Random Walk
The most simple move there is: taking a random step.

As you can see, you simply subclass the ``BaseAgent``, setup a random walk in one line of code and add it to the environment

```python
class Agent(BaseAgent):
def step(self):
self.random_walk()

# Define all agents
agent1 = Agent(2,3,curiosity=5,color = GREEN)
agent2 = Agent(17,7,curiosity=2,color = BLUE)
agent3 = Agent(8,1,curiosity=20,color = RED)

# Define environment
env = GridEnvironment(width = 20,height = 10,cell_size = 20,show_grid = True)

# Add agents to the environment
env.add_object([agent1,agent2,agent3])
env.render()

# Make simulation
sim = Simulation(env,fps = 10,name="RandomWalk")
_,_ = sim.run_episode(n_steps = 20,save = True,replay = True,save_format="gif")
```
![](./img/RandomWalk_1631837258.gif)

## Wandering
If you need an agent to explore the environment, you can use the ``.wander()`` function.
Basically the agent will walk straight in a direction, and change direction at some point using a ``curiosity`` factor - ie for ``curiosity = 5`` it will change direction every 5 steps (in the example below, compare the behavior of the 3 agents with a different curiosity).

In a ``GridEnvironment``, the direction angle is approximated by sampling horizontal and vertical movements on the grid to match the angle as best as possible.

```python
class Agent(BaseAgent):
def step(self):
self.wander()
```
![](./img/RandomWalk_1631836560.gif)


## Pathfinding
Another useful behavior is moving towards a point. This is done using pathfinding algorithms.

If there are some obstacles, you may require advanced pathfinding (tutorial to come) which is more expensive to compute. Without obstacles you can use naive pathfinding.

Just use the ``.move_towards()`` function and your agents will move towards a given target

```python
class Agent(BaseAgent):
def step(self):
self.move_towards(0,0,naive = True)
```
![](./img/RandomWalk_1631837025.gif)
16 changes: 16 additions & 0 deletions docs/tutorials/objects.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Objects
Understanding the different objects in ``Westworld``

> WIP
## Agents

## Obstacles

## Triggers

## Collectibles

## Creating multiple objects with the spawner

## Layers
Empty file added docs/tutorials/other.md
Empty file.
103 changes: 103 additions & 0 deletions docs/tutorials/quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Quickstart

Getting started with ``westworld`` in a few lines of code - Westworld is multi-agent simulation library in Python. You can use it to simulate spatial environments with agents moving, interacting with each other, finding their path and avoiding obstacles, ...

In this quickstart, we will create a super simple ecosystem of rabbits competing and looking for food and eating them when they find it.

![](./img/Quickstart_1631837803.gif)


## Preparing the basic imports
We will import necessary objects classes, the environment and simulation wrappers.
```python
from westworld.environment import GridEnvironment
from westworld.agents import BaseAgent
from westworld.objects import BaseCollectible
from westworld.simulation import Simulation
```
## Defining the food to collect
Objects that are collected by agents and then disappear are called ``Collectibles``. They can trigger something once an agent collects them and then are destroyed. We will then subclass this Collectible class to create our Food object.
```python
class Food(BaseCollectible):
pass
```
Yes this class does nothing. For now. Actually we will just use the name of the class ``Food`` in the Rabbit behavior function to look for those collectibles. Of course we could add more features to this collectible, for example increase the life of the rabbit once eaten.


## Defining the rabbits
We will then define a rabbit whose behavior will be described in a ``.step()`` function - ie everything that happens between t and t+1

- Looking for the closest food piece using helper function ``.find_closest()`` (we will use the class name here to find for the ``Food`` objects)
- If it finds any, the rabbit will move towards the object to collect it using ``.move_towards()`` helper function until collecting it and going to the next closest
- If there aren't anymore food, the rabbit will just ``.wander()`` around the environment


```python
class Rabbit(BaseAgent):

def __init__(self,x,y):
super().__init__(x,y,color = (229, 229, 229),curiosity = 5)

def step(self):

# Find closest food
targets = self.find_closest(name = "Food",k = 1)

# If there is still food, move towards the food
if len(targets) > 0:

target = targets[0]

# Use naive pathfinding for faster computation as there is no obstacle
self.move_towards(obj = target,naive = True)

# Otherwise just wandering
# Changing direction every n steps where n = curiosity
else:
self.wander()
```

## Preparing spawners
Spawners will help us add multiple rabbits and food pieces at the same time, it's a generator of custom objects in your environment.
We will simply use a lambda function:

```
rabbit_spawner = lambda x,y : Rabbit(x,y)
food_spawner = lambda x,y : Food(x,y,color = (220,150,50),img_asset = "ball")
```

For the Food object we use default arguments of ``BaseCollectible`` objects to change the food color and shape (make it look like a ball).

## Defining the environment
Now we need to put those food and rabbits somewhere, let's create a grid environment. There are many arguments to define width, height, cell size, colors, etc...
```python
env = GridEnvironment(20,10,20,show_grid = True,background_color=(102, 178, 102),grid_color=(127, 191, 127),toroidal=True)
```

We now add a few rabbits and food pieces using the spawner.
```python
env.spawn(rabbit_spawner,3)
env.spawn(food_spawner,20)
```

And we initalize the environment and visualize it using ``.render()`` function
```python
env.render()
```

## Launching the simulation
Next step is to simulate what happens in the environment with the step rules that we defined. We now wrap the environment in a ``Simulation`` object and run an episode of 50 steps. We save the simulation to a gif to be visualized.

```python
sim = Simulation(env,fps = 10,name="Quickstart")
_,_ = sim.run_episode(n_steps = 50,save = True,replay = True,save_format="gif",)
```

We get the following simulation:

![](./img/Quickstart_1631837803.gif)

## Going further
There are so many behaviors you can customize using precoded functions in westworld or write your own, you can add obstacles, put the agents in a maze, define other agents, complexify agent behavior, log information over time. You are not even obliged to use a grid environment and can work in a continuous environment.

For this ecosystem simulation, there are also many improvements you can do: add rabbit reproduction, short sightedness, introduce predators or different type of food. We will see a more complex example in another tutorial.
9 changes: 7 additions & 2 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ nav:
- Home: index.md
- References: references.md
- Tutorials:
- Simple pathfinding: tutorials/simple_pathfinding.md
- Simple vision range: tutorials/simple_visionrange.md
- Basic:
- Quickstart: tutorials/quickstart.md
- Movements: tutorials/movements.md
- Objects: tutorials/objects.md
- Extra features:
- Maze generation: tutorials/maze.md
- Other: tutorials/other.md
- API:
- api/index.md
4 changes: 2 additions & 2 deletions notebooks/20210709 - Foxes vs Rabbits.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"source": [
"class Food(BaseCollectible):\n",
" def __init__(self,x,y):\n",
" super().__init__(x,y,color = (220,150,50),img_asset = \"ball\")"
" super().__init__(x,y,)"
]
},
{
Expand Down Expand Up @@ -982,7 +982,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand Down
Loading

0 comments on commit 088f2c1

Please sign in to comment.