diff --git a/.github/ISSUE_TEMPLATE/---bug-report.md b/.github/ISSUE_TEMPLATE/---bug-report.md index d3712f58..4d25a843 100644 --- a/.github/ISSUE_TEMPLATE/---bug-report.md +++ b/.github/ISSUE_TEMPLATE/---bug-report.md @@ -38,7 +38,7 @@ Steps to reproduce the behavior: - How you installed MARO (`pip`, `source`): - OS (`Linux`, `Windows`, `macOS`): - Python version (`3.6`, `3.7`): -- Docker image (e.g., arthursjiang/maro:cpu[5f36ed]): +- Docker image (e.g., maro2020/maro:latest): - CPU/GPU: - Any other relevant information: diff --git a/.github/workflows/deploy_docker_image.yml b/.github/workflows/deploy_docker_image.yml index 2d186975..a876abf9 100644 --- a/.github/workflows/deploy_docker_image.yml +++ b/.github/workflows/deploy_docker_image.yml @@ -30,7 +30,7 @@ jobs: run: | pip install -r ./maro/requirements.build.txt cython ./maro/backends/backend.pyx ./maro/backends/np_backend.pyx ./maro/backends/raw_backend.pyx ./maro/backends/frame.pyx --cplus -3 -E NODES_MEMORY_LAYOUT=ONE_BLOCK -X embedsignature=True - cat ./maro/__misc__.py | grep __version__ | egrep -o [0-9].[0-9].[0-9,a-z]+ | { read version; docker build -f ./docker_files/cpu.play.df . -t ${{ secrets.DOCKER_HUB_USERNAME }}/maro:cpu -t ${{ secrets.DOCKER_HUB_USERNAME }}/maro:latest -t ${{ secrets.DOCKER_HUB_USERNAME }}/maro:cpu-$version; } + cat ./maro/__misc__.py | grep __version__ | egrep -o [0-9].[0-9].[0-9,a-z]+ | { read version; docker build -f ./docker_files/cpu.playground.df . -t ${{ secrets.DOCKER_HUB_USERNAME }}/maro:cpu -t ${{ secrets.DOCKER_HUB_USERNAME }}/maro:latest -t ${{ secrets.DOCKER_HUB_USERNAME }}/maro:cpu-$version; } - name: Login docker hub run: | diff --git a/README.md b/README.md index e09ed527..13e3290d 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ [![Platform](https://raw.githubusercontent.com/microsoft/maro/master/docs/source/images/badges/platform.svg)](https://pypi.org/project/pymaro/) [![Python Versions](https://img.shields.io/pypi/pyversions/pymaro.svg?logo=python&logoColor=white)](https://pypi.org/project/pymaro/#files) [![Code Size](https://img.shields.io/github/languages/code-size/microsoft/maro)](https://github.com/microsoft/maro) -[![Docker Size](https://img.shields.io/docker/image-size/arthursjiang/maro)](https://hub.docker.com/repository/docker/arthursjiang/maro/tags?page=1) +[![Docker Size](https://img.shields.io/docker/image-size/maro2020/maro)](https://hub.docker.com/repository/docker/maro2020/maro/tags?page=1) [![Issues](https://img.shields.io/github/issues/microsoft/maro)](https://github.com/microsoft/maro/issues) [![Pull Requests](https://img.shields.io/github/issues-pr/microsoft/maro)](https://github.com/microsoft/maro/pulls) [![Dependencies](https://img.shields.io/librariesio/github/microsoft/maro)](https://libraries.io/pypi/pymaro) [![test](https://github.com/microsoft/maro/workflows/test/badge.svg)](https://github.com/microsoft/maro/actions?query=workflow%3Atest) [![build](https://github.com/microsoft/maro/workflows/build/badge.svg)](https://github.com/microsoft/maro/actions?query=workflow%3Abuild) -[![docker](https://github.com/microsoft/maro/workflows/docker/badge.svg)](https://hub.docker.com/repository/docker/arthursjiang/maro) +[![docker](https://github.com/microsoft/maro/workflows/docker/badge.svg)](https://hub.docker.com/repository/docker/maro2020/maro) [![docs](https://readthedocs.org/projects/maro/badge/?version=latest)](https://maro.readthedocs.io/) [![PypI Versions](https://img.shields.io/pypi/v/pymaro)](https://pypi.org/project/pymaro/#files) [![Wheel](https://img.shields.io/pypi/wheel/pymaro)](https://pypi.org/project/pymaro/#files) @@ -23,8 +23,8 @@ [![Lint](https://github.com/microsoft/maro/workflows/lint/badge.svg)](https://github.com/microsoft/maro/actions?query=workflow%3Alint) [![Coverage](https://img.shields.io/codecov/c/github/microsoft/maro)](https://codecov.io/gh/microsoft/maro) [![Downloads](https://img.shields.io/pypi/dm/pymaro)](https://pypi.org/project/pymaro/#files) -[![Docker Pulls](https://img.shields.io/docker/pulls/arthursjiang/maro)](https://hub.docker.com/repository/docker/arthursjiang/maro) -[![Play with MARO](https://raw.githubusercontent.com/microsoft/maro/master/docs/source/images/badges/play_with_maro.svg)](https://hub.docker.com/r/arthursjiang/maro) +[![Docker Pulls](https://img.shields.io/docker/pulls/maro2020/maro)](https://hub.docker.com/repository/docker/maro2020/maro) +[![Play with MARO](https://raw.githubusercontent.com/microsoft/maro/master/docs/source/images/badges/play_with_maro.svg)](https://hub.docker.com/r/maro2020/maro) # [![MARO LOGO](./docs/source/images/logo.svg)](https://maro.readthedocs.io/en/latest/) @@ -58,6 +58,8 @@ of user-defined functions for message auto-handling, cluster provision, and job | `examples` | Showcase of MARO. | | `notebooks` | MARO quick-start notebooks. | +*Try [MARO playground](#run-playground) to have a quick experience.* + ## Install MARO from [PyPI](https://pypi.org/project/pymaro/#files) *Notes: The CLI commands (including the visualization tool) are not included in pymaro package. To enable these support, you need to install from source.* @@ -185,14 +187,13 @@ maro inspector dashboard --source_path ./dump_data/YOUR_SNAPSHOT_DUMP_FOLDER ## Run Playground -- Pull from [Docker Hub](https://hub.docker.com/repository/registry-1.docker.io/arthursjiang/maro/tags?page=1) +- Pull from [Docker Hub](https://hub.docker.com/r/maro2020/playground) ```sh # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 arthursjiang/maro:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground ``` - Build from source @@ -204,9 +205,8 @@ maro inspector dashboard --source_path ./dump_data/YOUR_SNAPSHOT_DUMP_FOLDER # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 maro/playground:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground ``` - Windows @@ -217,9 +217,8 @@ maro inspector dashboard --source_path ./dump_data/YOUR_SNAPSHOT_DUMP_FOLDER # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 maro/playground:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground ``` ## Contributing diff --git a/docker_files/cpu.play.df b/docker_files/cpu.playground.df similarity index 69% rename from docker_files/cpu.play.df rename to docker_files/cpu.playground.df index 1c999f1e..43def890 100644 --- a/docker_files/cpu.play.df +++ b/docker_files/cpu.playground.df @@ -1,20 +1,8 @@ -FROM python:3.6 +FROM python:3.7 WORKDIR /maro_playground -# Setup notebook -ADD ./notebooks ./notebooks -RUN /usr/local/bin/python -m pip install --upgrade pip -RUN pip install -r ./notebooks/requirements.nb.txt -RUN jupyter contrib nbextension install --system -RUN jt -t onedork -fs 95 -altp -tfs 11 -nfs 115 -cellw 88% -T - - -# Install redis -RUN wget http://download.redis.io/releases/redis-6.0.6.tar.gz; tar xzf redis-6.0.6.tar.gz; cd redis-6.0.6; make -RUN rm redis-6.0.6.tar.gz - -# Install others +# Install zsh and other packages for the terminal usage RUN apt-get -o Acquire::Check-Valid-Until=false -o Acquire::Check-Date=false update RUN apt-get install -y zsh RUN apt-get install -y htop @@ -23,42 +11,36 @@ RUN wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh - RUN chsh -s `which zsh` && wget https://raw.githubusercontent.com/ArthurJiang/config/master/.zshrc -O ~/.zshrc RUN apt-get install -y npm RUN rm -rf /var/lib/apt/lists/* + +# Install redis +RUN wget http://download.redis.io/releases/redis-6.0.6.tar.gz; tar xzf redis-6.0.6.tar.gz; cd redis-6.0.6; make +RUN rm redis-6.0.6.tar.gz RUN npm install -g redis-commander +# Setup notebook +ADD ./notebooks ./notebooks +RUN /usr/local/bin/python -m pip install --upgrade pip +RUN pip install -r ./notebooks/requirements.nb.txt +RUN jupyter contrib nbextension install --system +RUN jt -t onedork -fs 95 -altp -tfs 11 -nfs 115 -cellw 88% -T +RUN rm ./notebooks/*.txt +RUN rm ./notebooks/*.sh + # Add examples ADD ./examples ./examples +ADD ./examples/requirements.ex.txt ./examples/requirements.ex.txt +RUN pip install -r ./examples/requirements.ex.txt +RUN rm ./examples/requirements.ex.txt -# Add local docs -ADD ./docs ./docs -ADD ./maro ./maro -ADD setup.py setup.py -ADD ./scripts ./scripts -RUN bash scripts/install_maro.sh -RUN pip install -U -r ./docs/requirements.docs.txt -RUN cd docs; make html -RUN rm -rf ./maro -RUN rm setup.py -RUN rm -rf ./scripts +# Install MARO +RUN pip install pymaro +ENV PYTHONPATH ./ # Add run cmd ADD ./scripts/run_playground.sh ./run.sh -# Add readme +# Add README ADD ./playground.md ./README.md -# Clean -RUN rm ./notebooks/*.txt -RUN rm ./notebooks/*.sh -RUN rm -r ./docs/source -RUN rm ./docs/make.bat -RUN rm ./docs/Makefile -RUN rm ./docs/README.md -RUN rm ./docs/requirements.docs.txt -RUN rm -rf ./build -RUN rm -rf ./pymaro.egg-info - -# Install maro -RUN pip install pymaro - # Start service CMD ["/bin/bash", "./run.sh"] diff --git a/docs/source/examples/greedy_policy_citi_bike.rst b/docs/source/examples/greedy_policy_citi_bike.rst index 20fa2062..601c016a 100644 --- a/docs/source/examples/greedy_policy_citi_bike.rst +++ b/docs/source/examples/greedy_policy_citi_bike.rst @@ -76,4 +76,4 @@ This environment is driven by `real trip history data `_. + All related code snippets are supported in `maro playground `_. diff --git a/docs/source/examples/multi_agent_dqn_cim.rst b/docs/source/examples/multi_agent_dqn_cim.rst index 0024ca00..bc411644 100644 --- a/docs/source/examples/multi_agent_dqn_cim.rst +++ b/docs/source/examples/multi_agent_dqn_cim.rst @@ -19,7 +19,7 @@ in the roll-out loop. In this example, to or unloaded from the vessel) to action objects that can be executed by the environment. * ``get_offline_reward`` computes the reward of a given action as a linear combination of fulfillment and shortage within a future time frame. - * ``on_finish`` processes a complete trajectory into data that can be used directly by the learning agents. + * ``on_finish`` processes a complete trajectory into data that can be used directly by the learning agents. .. code-block:: python @@ -27,7 +27,7 @@ in the roll-out loop. In this example, def __init__( self, env, *, port_attributes, vessel_attributes, action_space, look_back, max_ports_downstream, reward_time_window, fulfillment_factor, shortage_factor, time_decay, - finite_vessel_space=True, has_early_discharge=True + finite_vessel_space=True, has_early_discharge=True ): super().__init__(env) self.port_attributes = port_attributes @@ -113,7 +113,7 @@ Agent The out-of-the-box DQN is used as our agent. -.. code-block:: python +.. code-block:: python agent_config = { "model": ..., "optimization": ..., @@ -149,7 +149,7 @@ The learner's side requires a concrete learner class that inherits from ``AbsLea method which contains the main training loop. Here the implementation is similar to the single-threaded version except that the ``collect`` method is used to obtain roll-out data from the actors (since the roll-out executors are located on the actors' side). The agents created here are where training occurs and hence always contains the -latest policies. +latest policies. .. code-block:: python def cim_dqn_learner(): @@ -165,4 +165,4 @@ latest policies. .. note:: - All related code snippets are supported in `maro playground `_. + All related code snippets are supported in `maro playground `_. diff --git a/docs/source/index.rst b/docs/source/index.rst index 8ef7efaf..2b3fe29b 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -32,45 +32,35 @@ Quick Start .. code-block:: python from maro.simulator import Env - from maro.simulator.scenarios.cim.common import Action + from maro.simulator.scenarios.cim.common import Action, ActionType, DecisionEvent - # Initialize an environment with a specific scenario, related topology. - # In Container Inventory Management, 1 tick means 1 day, here durations=100 means a length of 100 days + from random import randint + + # Initialize an Env for cim scenario env = Env(scenario="cim", topology="toy.5p_ssddd_l0.0", start_tick=0, durations=100) - # Query environment summary, which includes business instances, intra-instance attributes, etc. - print(env.summary) + metrics: object = None + decision_event: DecisionEvent = None + is_done: bool = False + action: Action = None - for ep in range(2): - # Gym-like step function. - metrics, decision_event, is_done = env.step(None) + # Start the env with a None Action + metrics, decision_event, is_done = env.step(None) - while not is_done: - past_week_ticks = [ - x for x in range(decision_event.tick - 7, decision_event.tick) - ] - decision_port_idx = decision_event.port_idx - intr_port_infos = ["booking", "empty", "shortage"] + while not is_done: + # Generate a random Action according to the action_scope in DecisionEvent + action_scope = decision_event.action_scope + to_discharge = action_scope.discharge > 0 and randint(0, 1) > 0 - # Query the snapshot list of the environment to get the information of - # the booking, empty container inventory, shortage of the decision port in the past week. - past_week_info = env.snapshot_list["ports"][ - past_week_ticks : decision_port_idx : intr_port_infos - ] + action = Action( + decision_event.vessel_idx, + decision_event.port_idx, + randint(0, action_scope.discharge if to_discharge else action_scope.load), + ActionType.DISCHARGE if to_discharge else ActionType.LOAD + ) - dummy_action = Action( - vessel_idx=decision_event.vessel_idx, - port_idx=decision_event.port_idx, - quantity=0 - ) - - # Drive environment with dummy action (no repositioning). - metrics, decision_event, is_done = env.step(dummy_action) - - # Query environment business metrics at the end of an episode, - # it is your optimized object (usually includes multi-target). - print(f"ep: {ep}, environment metrics: {env.metrics}") - env.reset() + # Respond the environment with the generated Action + metrics, decision_event, is_done = env.step(action) Contents ---------- diff --git a/docs/source/installation/playground.rst b/docs/source/installation/playground.rst index 34ffc33f..e7ba52b6 100644 --- a/docs/source/installation/playground.rst +++ b/docs/source/installation/playground.rst @@ -2,16 +2,15 @@ Playground Docker Image ======================= -Pull from `Docker Hub `_ +Pull from `Docker Hub `_ ------------------------------------------------------------------------------------------------------------------ .. code-block:: sh # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 arthursjiang/maro:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground Run from Source --------------- @@ -25,9 +24,8 @@ Run from Source # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 maro/playground:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground * Windows @@ -38,9 +36,8 @@ Run from Source # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 maro/playground:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground Major Services in Playground ---------------------------- @@ -54,15 +51,12 @@ Major Services in Playground * - ``Redis Commander`` - Redis web GUI. - http://127.0.0.1:40009 - * - ``Read the Docs`` - - Local host docs. - - http://127.0.0.1:40010 * - ``Jupyter Lab`` - Jupyter lab with MARO environment, examples, notebooks. - - http://127.0.0.1:40011 + - http://127.0.0.1:40010 -*(If you use other port mapping, remember to change the port number.)* +*(Remember to change ports if you use different ports mapping.)* Major Materials in Root Folder ------------------------------ @@ -78,4 +72,4 @@ Major Materials in Root Folder - Quick-start tutorial. -*(Those not mentioned in the table can be ignored.)* +*(The ones not mentioned in this table can be ignored.)* diff --git a/docs/source/scenarios/container_inventory_management.rst b/docs/source/scenarios/container_inventory_management.rst index 3e5e8ab9..54cce05d 100644 --- a/docs/source/scenarios/container_inventory_management.rst +++ b/docs/source/scenarios/container_inventory_management.rst @@ -571,10 +571,8 @@ Once we get a ``DecisionEvent`` from the environment, we should respond with an * **vessel_idx** (int): The id of the vessel/operation object of the port/agent. * **port_idx** (int): The id of the port/agent that take this action. - * **quantity** (int): The sign of this value denotes different meanings: - - * Positive quantity means discharging empty containers from vessel to port. - * Negative quantity means loading empty containers from port to vessel. + * **action_type** (ActionType): Whether to load or discharge empty containers in this action. + * **quantity** (int): The quantity of empty containers to be loaded/discharged. Example ^^^^^^^ @@ -583,61 +581,36 @@ Here we will show you a simple example of interaction with the environment in random mode, we hope this could help you learn how to use the environment interfaces: .. code-block:: python + from maro.simulator import Env + from maro.simulator.scenarios.cim.common import Action, ActionType, DecisionEvent - from maro.simulator import Env - from maro.simulator.scenarios.cim.common import Action, DecisionEvent + from random import randint - import random + # Initialize an Env for cim scenario + env = Env(scenario="cim", topology="toy.5p_ssddd_l0.0", start_tick=0, durations=100) - # Initialize an environment of CIM scenario, with a specific topology. - # In Container Inventory Management, 1 tick means 1 day, durations=100 here indicates a length of 100 days. - env = Env(scenario="cim", topology="toy.5p_ssddd_l0.0", start_tick=0, durations=100) + metrics: object = None + decision_event: DecisionEvent = None + is_done: bool = False + action: Action = None - # Query for the environment summary, the business instances and intra-instance attributes - # will be listed in the output for your reference. - print(env.summary) + # Start the env with a None Action + metrics, decision_event, is_done = env.step(None) - metrics: object = None - decision_event: DecisionEvent = None - is_done: bool = False - action: Action = None + while not is_done: + # Generate a random Action according to the action_scope in DecisionEvent + action_scope = decision_event.action_scope + to_discharge = action_scope.discharge > 0 and randint(0, 1) > 0 - num_episode = 2 - for ep in range(num_episode): - # Gym-like step function. - metrics, decision_event, is_done = env.step(None) + action = Action( + decision_event.vessel_idx, + decision_event.port_idx, + randint(0, action_scope.discharge if to_discharge else action_scope.load), + ActionType.DISCHARGE if to_discharge else ActionType.LOAD + ) - while not is_done: - past_week_ticks = [ - x for x in range(decision_event.tick - 7, decision_event.tick) - ] - decision_port_idx = decision_event.port_idx - intr_port_infos = ["booking", "empty", "shortage"] - - # Query the snapshot list of this environment to get the information of - # the booking, empty, shortage of the decision port in the past week. - past_week_info = env.snapshot_list["ports"][ - past_week_ticks : decision_port_idx : intr_port_infos - ] - - # Generate a random Action according to the action_scope in DecisionEvent. - random_quantity = random.randint( - -decision_event.action_scope.load, - decision_event.action_scope.discharge - ) - action = Action( - vessel_idx=decision_event.vessel_idx, - port_idx=decision_event.port_idx, - quantity=random_quantity - ) - - # Drive the environment with the random action. - metrics, decision_event, is_done = env.step(action) - - # Query for the environment business metrics at the end of each episode, - # it is usually users' optimized object in CIM scenario (usually includes multi-target). - print(f"ep: {ep}, environment metrics: {env.metrics}") - env.reset() + # Respond the environment with the generated Action + metrics, decision_event, is_done = env.step(action) Jump to `this notebook `_ for a quick experience. @@ -646,7 +619,7 @@ Visualization ------------- The resource holders in this scenario is the port and vessel. -In order to facilitate users to select specific data and +In order to facilitate users to select specific data and observe the overall or partial data trend, the visualization tool provides data selection options in two dimensions: Inter-epoch view & Intra-epoch view. diff --git a/examples/cim/dqn/main.py b/examples/cim/dqn/main.py index 3055ed74..8cf3c679 100644 --- a/examples/cim/dqn/main.py +++ b/examples/cim/dqn/main.py @@ -23,7 +23,7 @@ sys.path.insert(0, cim_example_path) from common import CIMTrajectory, common_config from dqn.config import agent_config, training_config -log_dir = join(cim_dqn_path, "logs") +log_dir = join(cim_dqn_path, "log") makedirs(log_dir, exist_ok=True) @@ -74,7 +74,7 @@ if __name__ == "__main__": "-w", "--whoami", type=int, choices=[0, 1, 2], default=0, help="Identity of this process: 0 - multi-process mode, 1 - learner, 2 - actor" ) - + args = parser.parse_args() if args.whoami == 0: actor_processes = [Process(target=cim_dqn_actor) for _ in range(training_config["num_actors"])] diff --git a/examples/hello_world/cim/hello.py b/examples/hello_world/cim/hello.py index 879e497a..3e564775 100644 --- a/examples/hello_world/cim/hello.py +++ b/examples/hello_world/cim/hello.py @@ -1,25 +1,19 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. +from random import seed, randint + from maro.simulator import Env from maro.simulator.scenarios.cim.common import Action, ActionType if __name__ == "__main__": - start_tick = 0 - durations = 100 # 100 days - - opts = dict() - """ - enable-dump-snapshot parameter means business_engine needs dump snapshot data before reset. - If you leave value to empty string, it will dump to current folder. - For getting dump data, please uncomment below line and specify dump destination folder. - """ # Initialize an environment with a specific scenario, related topology. - env = Env(scenario="cim", topology="global_trade.22p_l0.1", - start_tick=start_tick, durations=durations) + env = Env(scenario="cim", topology="global_trade.22p_l0.1", start_tick=0, durations=100) + # To reset environmental data before starting a new experiment. env.reset() + # Query environment summary, which includes business instances, intra-instance attributes, etc. print(env.summary) @@ -28,25 +22,18 @@ if __name__ == "__main__": metrics, decision_event, is_done = env.step(None) while not is_done: - past_week_ticks = [x for x in range( - max(decision_event.tick - 7, 0), decision_event.tick)] - decision_port_idx = decision_event.port_idx - intr_port_infos = ["booking", "empty", "shortage"] + action_scope = decision_event.action_scope + to_discharge = action_scope.discharge > 0 and randint(0, 1) > 0 - # Query the decision port booking, empty container inventory, shortage information in the past week - past_week_info = env.snapshot_list["ports"][past_week_ticks: - decision_port_idx: - intr_port_infos] - - dummy_action = Action( + random_action = Action( decision_event.vessel_idx, decision_event.port_idx, - 0, - ActionType.LOAD + randint(0, action_scope.discharge if to_discharge else action_scope.load), + ActionType.DISCHARGE if to_discharge else ActionType.LOAD ) # Drive environment with dummy action (no repositioning) - metrics, decision_event, is_done = env.step(dummy_action) + metrics, decision_event, is_done = env.step(random_action) # Query environment business metrics at the end of an episode, # it is your optimized object (usually includes multi-target). diff --git a/examples/hello_world/cim/hello_geo_vis.py b/examples/hello_world/cim/hello_geo_vis.py index 54f15994..d358a90e 100644 --- a/examples/hello_world/cim/hello_geo_vis.py +++ b/examples/hello_world/cim/hello_geo_vis.py @@ -9,32 +9,25 @@ os.environ["MARO_STREAMIT_ENABLED"] = "true" os.environ["MARO_STREAMIT_EXPERIMENT_NAME"] = "experiment_example" +from random import seed, randint + from maro.simulator import Env -from maro.simulator.scenarios.cim.common import Action, ActionType +from maro.simulator.scenarios.cim.common import Action, ActionScope, ActionType from maro.streamit import streamit if __name__ == "__main__": - start_tick = 0 - durations = 100 # 100 days + seed(0) + NUM_EPISODE = 2 - opts = dict() with streamit: - """ - enable-dump-snapshot parameter means business_engine needs dump snapshot data before reset. - If you leave value to empty string, it will dump to current folder. - For getting dump data, please uncomment below line and specify dump destination folder. - """ - # Initialize an environment with a specific scenario, related topology. - env = Env(scenario="cim", topology="global_trade.22p_l0.1", - start_tick=start_tick, durations=durations, options=opts) + env = Env(scenario="cim", topology="global_trade.22p_l0.1", start_tick=0, durations=100) + # To reset environmental data before starting a new experiment. env.reset() - # Query environment summary, which includes business instances, intra-instance attributes, etc. - print(env.summary) - for ep in range(2): + for ep in range(NUM_EPISODE): # Tell streamit we are in a new episode. streamit.episode(ep) @@ -42,25 +35,18 @@ if __name__ == "__main__": metrics, decision_event, is_done = env.step(None) while not is_done: - past_week_ticks = [x for x in range( - max(decision_event.tick - 7, 0), decision_event.tick)] - decision_port_idx = decision_event.port_idx - intr_port_infos = ["booking", "empty", "shortage"] + action_scope = decision_event.action_scope + to_discharge = action_scope.discharge > 0 and randint(0, 1) > 0 - # Query the decision port booking, empty container inventory, shortage information in the past week - past_week_info = env.snapshot_list["ports"][past_week_ticks: - decision_port_idx: - intr_port_infos] - - dummy_action = Action( + random_action = Action( decision_event.vessel_idx, decision_event.port_idx, - 0, - ActionType.LOAD + randint(0, action_scope.discharge if to_discharge else action_scope.load), + ActionType.DISCHARGE if to_discharge else ActionType.LOAD ) # Drive environment with dummy action (no repositioning) - metrics, decision_event, is_done = env.step(dummy_action) + metrics, decision_event, is_done = env.step(random_action) # Query environment business metrics at the end of an episode, # it is your optimized object (usually includes multi-target). diff --git a/examples/hello_world/cim/hello_streamlit.py b/examples/hello_world/cim/hello_streamlit.py index 1875ff5f..31855cfb 100644 --- a/examples/hello_world/cim/hello_streamlit.py +++ b/examples/hello_world/cim/hello_streamlit.py @@ -1,13 +1,15 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. +from random import seed, randint + from maro.simulator import Env from maro.simulator.scenarios.cim.common import Action, ActionType if __name__ == "__main__": - start_tick = 0 - durations = 100 # 100 days + seed(0) + NUM_EPISODE = 2 opts = dict() """ @@ -20,37 +22,29 @@ if __name__ == "__main__": # Initialize an environment with a specific scenario, related topology. env = Env( scenario="cim", topology="global_trade.22p_l0.1", - start_tick=start_tick, durations=durations, options=opts + start_tick=0, durations=100, options=opts ) + # To reset environmental data before starting a new experiment. env.reset() - # Query environment summary, which includes business instances, intra-instance attributes, etc. - print(env.summary) - for ep in range(2): + for ep in range(NUM_EPISODE): # Gym-like step function. metrics, decision_event, is_done = env.step(None) while not is_done: - past_week_ticks = [x for x in range( - max(decision_event.tick - 7, 0), decision_event.tick)] - decision_port_idx = decision_event.port_idx - intr_port_infos = ["booking", "empty", "shortage"] + action_scope = decision_event.action_scope + to_discharge = action_scope.discharge > 0 and randint(0, 1) > 0 - # Query the decision port booking, empty container inventory, shortage information in the past week - past_week_info = env.snapshot_list["ports"][past_week_ticks: - decision_port_idx: - intr_port_infos] - - dummy_action = Action( + random_action = Action( decision_event.vessel_idx, decision_event.port_idx, - 0, - ActionType.LOAD + randint(0, action_scope.discharge if to_discharge else action_scope.load), + ActionType.DISCHARGE if to_discharge else ActionType.LOAD ) # Drive environment with dummy action (no repositioning) - metrics, decision_event, is_done = env.step(dummy_action) + metrics, decision_event, is_done = env.step(random_action) # Query environment business metrics at the end of an episode, # it is your optimized object (usually includes multi-target). diff --git a/examples/hello_world/test_vm.py b/examples/hello_world/test_vm.py deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/requirements.ex.txt b/examples/requirements.ex.txt new file mode 100644 index 00000000..dbdc8c56 --- /dev/null +++ b/examples/requirements.ex.txt @@ -0,0 +1 @@ +PuLP==2.1 diff --git a/examples/vector_env/hello.py b/examples/vector_env/hello.py index 3a1eec24..1d630373 100644 --- a/examples/vector_env/hello.py +++ b/examples/vector_env/hello.py @@ -1,46 +1,66 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT license. -from maro.simulator.scenarios.cim.common import Action, DecisionEvent +from enum import Enum +from maro.simulator.scenarios.cim.common import Action, ActionType, DecisionEvent from maro.vector_env import VectorEnv +class VectorEnvUsage(Enum): + PUSH_ONE_FORWARD = "push the first environment forward and left others behind" + PUSH_ALL_FORWARD = "push all environments forward together" + +USAGE = VectorEnvUsage.PUSH_ONE_FORWARD if __name__ == "__main__": with VectorEnv(batch_num=4, scenario="cim", topology="toy.5p_ssddd_l0.0", durations=100) as env: - for ep in range(2): - print("current episode:", ep) + for USAGE in [VectorEnvUsage.PUSH_ONE_FORWARD, VectorEnvUsage.PUSH_ALL_FORWARD]: + print(f"******************************************************") + print(f"Mode: {USAGE} ({USAGE.value})") + intermediate_status_reported = False metrics, decision_event, is_done = (None, None, False) while not is_done: action = None - # Usage: - # 1. Only push speicified (1st for this example) environment, leave others behind - # if decision_event: - # env0_dec: DecisionEvent = decision_event[0] - - # # 1.1 After 1st environment is done, then others will push forward. - # if env0_dec: - # ss0 = env.snapshot_list["vessels"][env0_dec.tick:env0_dec.vessel_idx:"remaining_space"] - # action = {0: Action(env0_dec.vessel_idx, env0_dec.port_idx, -env0_dec.action_scope.load)} - - # 2. Only pass action to 1st environment (give None to other environments), - # but keep pushing all the environment, until the end if decision_event: env0_dec: DecisionEvent = decision_event[0] + # Showcase: how to access information from snapshot list in vector env. if env0_dec: ss0 = env.snapshot_list["vessels"][env0_dec.tick:env0_dec.vessel_idx:"remaining_space"] - action = [None] * env.batch_number + # 1. Only push specified (1st for this example) environment, leave others behind. + if USAGE == VectorEnvUsage.PUSH_ONE_FORWARD and env0_dec: + # Only action for the 1st Env. After 1st environment is done, then others will push forward. + action = { + 0: Action( + vessel_idx=env0_dec.vessel_idx, + port_idx=env0_dec.port_idx, + quantity=env0_dec.action_scope.load, + action_type=ActionType.LOAD + ) + } - # with a list of action, will push all environment to next step - action[0] = Action(env0_dec.vessel_idx, env0_dec.port_idx, -env0_dec.action_scope.load) + # 2. Only pass action to 1st environment (give None to other environments), + # but keep pushing all the environment, until the end + elif USAGE == VectorEnvUsage.PUSH_ALL_FORWARD and env0_dec: + # With a list of action, will push all environment to next step. + action = [None] * env.batch_number + action[0] = Action( + vessel_idx=env0_dec.vessel_idx, + port_idx=env0_dec.port_idx, + quantity=env0_dec.action_scope.load, + action_type=ActionType.LOAD + ) metrics, decision_event, is_done = env.step(action) - print("Final tick for each environment:", env.tick) - print("Final frame index for each environment:", env.frame_index) + if not intermediate_status_reported and env.tick[0] >= 99: + print(f"When env 0 reach tick {env.tick[0]}, ticks for each environment: {env.tick}") + intermediate_status_reported = True + + print(f"Final tick for each environment: {env.tick}") + print(f"Final frame index for each environment: {env.frame_index}") env.reset() diff --git a/maro/README.rst b/maro/README.rst index 9f40c362..bf583fab 100644 --- a/maro/README.rst +++ b/maro/README.rst @@ -11,7 +11,7 @@ .. image:: https://github.com/microsoft/maro/workflows/docker/badge.svg - :target: https://hub.docker.com/repository/docker/arthursjiang/maro + :target: https://hub.docker.com/repository/docker/maro2020/maro :alt: docker @@ -84,14 +84,14 @@ Install MARO from `PyPI `_ ---------------------------------------------------------------------- -* +* Max OS / Linux .. code-block:: sh pip install pymaro -* +* Windows .. code-block:: powershell @@ -105,20 +105,20 @@ Install MARO from Source (\ `Editable Mode `_ + * Windows: `Build Tools for Visual Studio 2017 `_ -* +* Enable Virtual Environment - * + * Mac OS / Linux .. code-block:: sh @@ -127,7 +127,7 @@ Install MARO from Source (\ `Editable Mode `_ +* + Pull from `Docker Hub `_ + .. code-block:: sh + docker pull maro2020/playground .. code-block:: sh # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 arthursjiang/maro:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground -* +* Build from source - * + * Mac OS / Linux .. code-block:: sh @@ -204,11 +205,10 @@ Run Playground # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 maro/playground:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground - * + * Windows .. code-block:: powershell @@ -218,9 +218,8 @@ Run Playground # Run playground container. # Redis commander (GUI for redis) -> http://127.0.0.1:40009 - # Local host docs -> http://127.0.0.1:40010 - # Jupyter lab with maro -> http://127.0.0.1:40011 - docker run -p 40009:40009 -p 40010:40010 -p 40011:40011 maro/playground:cpu + # Jupyter lab with maro -> http://127.0.0.1:40010 + docker run -p 40009:40009 -p 40010:40010 maro2020/playground Contributing ------------ diff --git a/maro/cli/maro_real_time_vis/start_maro_geo_vis.py b/maro/cli/maro_real_time_vis/start_maro_geo_vis.py index 6da7d62a..41bc326d 100644 --- a/maro/cli/maro_real_time_vis/start_maro_geo_vis.py +++ b/maro/cli/maro_real_time_vis/start_maro_geo_vis.py @@ -77,13 +77,13 @@ def start_geo_vis(start: str, experiment_name: str, front_end_port: int, **kwarg # Start front-end docker container. exec_path = os.path.dirname(inspect.getfile(inspect.currentframe())) - os.system("docker pull meroychen/geo_front_service") + os.system("docker pull maro2020/geo_front_service") os.system("docker stop geo-vis") os.system("docker rm geo-vis") if front_end_port is not None: - os.system(f"docker run -d -p {front_end_port}:8080 --name geo-vis meroychen/geo_front_service") + os.system(f"docker run -d -p {front_end_port}:8080 --name geo-vis maro2020/geo_front_service") else: - os.system("docker run -d -p 8080:8080 --name geo-vis meroychen/geo_front_service") + os.system("docker run -d -p 8080:8080 --name geo-vis maro2020/geo_front_service") back_end_path = f"{exec_path}/back_end/vis_app/app.py" os.system(f"python {back_end_path}") diff --git a/maro/event_buffer/__init__.py b/maro/event_buffer/__init__.py index 68caf7a1..11c7e0c2 100644 --- a/maro/event_buffer/__init__.py +++ b/maro/event_buffer/__init__.py @@ -6,5 +6,6 @@ from .cascade_event import CascadeEvent from .event_buffer import EventBuffer from .event_state import EventState from .maro_events import MaroEvents +from .typings import Event -__all__ = ["AtomEvent", "CascadeEvent", "EventBuffer", "EventState", "MaroEvents"] +__all__ = ["AtomEvent", "CascadeEvent", "Event", "EventBuffer", "EventState", "MaroEvents"] diff --git a/maro/simulator/scenarios/cim/common.py b/maro/simulator/scenarios/cim/common.py index 67c092eb..5901aed7 100644 --- a/maro/simulator/scenarios/cim/common.py +++ b/maro/simulator/scenarios/cim/common.py @@ -25,10 +25,11 @@ class Action: Args: vessel_idx (int): Which vessel will take action. port_idx (int): Which port will take action. - quantity (int): How many containers can be moved from vessel to port (negative in reverse). + action_type (ActionType): Whether the action is a Load or a Discharge. + quantity (int): How many containers are loaded/discharged in this Action. """ - summary_key = ["port_idx", "vessel_idx", "quantity"] + summary_key = ["port_idx", "vessel_idx", "action_type", "quantity"] def __init__(self, vessel_idx: int, port_idx: int, quantity: int, action_type: ActionType): self.vessel_idx = vessel_idx diff --git a/notebooks/bike_repositioning/interact_with_environment.ipynb b/notebooks/bike_repositioning/interact_with_environment.ipynb index b8cabb77..2b9bdf34 100644 --- a/notebooks/bike_repositioning/interact_with_environment.ipynb +++ b/notebooks/bike_repositioning/interact_with_environment.ipynb @@ -18,11 +18,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "12:03:56 | WARNING | \u001b[33mBinary data files for scenario: citi_bike topology: toy.3s_4t not found.\u001b[0m\n", - "12:03:56 | WARNING | \u001b[33mGenerating temp binary data file for scenario: citi_bike topology: toy.3s_4t pid: 129013. If you want to keep the data, please use MARO CLI command 'maro env data generate -s citi_bike -t toy.3s_4t' to generate the binary data files first.\u001b[0m\n", - "12:03:56 | INFO | \u001b[32mGenerating trip data for topology toy.3s_4t .\u001b[0m\n", - "12:03:57 | INFO | \u001b[32mBuilding binary data from ~/.maro/data/citi_bike/.source/.clean/toy.3s_4t/b37f36f2de334eb3/trips.csv to ~/.maro/data/citi_bike/.build/toy.3s_4t/b37f36f2de334eb3/trips.bin\u001b[0m\n", - "{'trip_requirements': 2156, 'bike_shortage': 1163, 'operation_number': 0}\n" + "{'trip_requirements': 2169, 'bike_shortage': 1199, 'operation_number': 0}\n" ] } ], @@ -73,7 +69,7 @@ "output_type": "stream", "text": [ "'The available scenarios in MARO:'\n", - "['cim', 'citi_bike']\n", + "['cim', 'citi_bike', 'vm_scheduling']\n", "\n", "'The predefined topologies in Citi Bike:'\n", "['ny.201801',\n", @@ -144,17 +140,28 @@ "name": "stdout", "output_type": "stream", "text": [ - "12:04:06 | WARNING | \u001b[33mBinary data files for scenario: citi_bike topology: toy.3s_4t not found.\u001b[0m\n", - "12:04:06 | WARNING | \u001b[33mGenerating temp binary data file for scenario: citi_bike topology: toy.3s_4t pid: 129013. If you want to keep the data, please use MARO CLI command 'maro env data generate -s citi_bike -t toy.3s_4t' to generate the binary data files first.\u001b[0m\n", - "12:04:06 | INFO | \u001b[32mGenerating trip data for topology toy.3s_4t .\u001b[0m\n", - "12:04:07 | INFO | \u001b[32mBuilding binary data from ~/.maro/data/citi_bike/.source/.clean/toy.3s_4t/0ad85988e84a43bd/trips.csv to ~/.maro/data/citi_bike/.build/toy.3s_4t/0ad85988e84a43bd/trips.bin\u001b[0m\n", "The current tick: 0.\n", "The current frame index: 0.\n", "There are 3 agents in this Env.\n", "There will be 48 snapshots in total.\n", "\n", "Env Summary:\n", - "{'node_detail': {'matrices': {'attributes': {'trips_adj': {'slots': 9,\n", + "{'event_payload': {'DeliverBike': ['from_station_idx',\n", + " 'to_station_idx',\n", + " 'number'],\n", + " 'RebalanceBike': ['station_idx',\n", + " 'tick',\n", + " 'frame_index',\n", + " 'type',\n", + " 'action_scope'],\n", + " 'RequireBike': ['timestamp',\n", + " 'durations',\n", + " 'src_station',\n", + " 'dest_station'],\n", + " 'ReturnBike': ['from_station_idx',\n", + " 'to_station_idx',\n", + " 'number']},\n", + " 'node_detail': {'matrices': {'attributes': {'trips_adj': {'slots': 9,\n", " 'type': 'i'}},\n", " 'number': 1},\n", " 'stations': {'attributes': {'bikes': {'slots': 1, 'type': 'i'},\n", @@ -275,19 +282,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "12:04:16 | WARNING | \u001b[33mBinary data files for scenario: citi_bike topology: toy.3s_4t not found.\u001b[0m\n", - "12:04:16 | WARNING | \u001b[33mGenerating temp binary data file for scenario: citi_bike topology: toy.3s_4t pid: 129013. If you want to keep the data, please use MARO CLI command 'maro env data generate -s citi_bike -t toy.3s_4t' to generate the binary data files first.\u001b[0m\n", - "12:04:16 | INFO | \u001b[32mGenerating trip data for topology toy.3s_4t .\u001b[0m\n", - "12:04:17 | INFO | \u001b[32mBuilding binary data from ~/.maro/data/citi_bike/.source/.clean/toy.3s_4t/56e2ca55ba6d4881/trips.csv to ~/.maro/data/citi_bike/.build/toy.3s_4t/56e2ca55ba6d4881/trips.bin\u001b[0m\n", "*************\n", - "DecisionEvent(tick=79, station_idx=1, type=DecisionType.Demand, action_scope={0: 0, 2: 0, 1: 30})\n", - "Action(from_station_idx=2, to_station_idx=1, number=0)\n", + "DecisionEvent {station_idx: 2, type: 'DecisionType.Demand', action_scope:{1: 0, 0: 0, 2: 30}}\n", + "Action {from_station_idx: 0, to_station_idx: '2', number:0}\n", "*************\n", - "DecisionEvent(tick=799, station_idx=2, type=DecisionType.Demand, action_scope={0: 0, 1: 0, 2: 30})\n", - "Action(from_station_idx=1, to_station_idx=2, number=0)\n", + "DecisionEvent {station_idx: 0, type: 'DecisionType.Demand', action_scope:{2: 1, 1: 1, 0: 30}}\n", + "Action {from_station_idx: 1, to_station_idx: '0', number:0}\n", "*************\n", - "DecisionEvent(tick=959, station_idx=2, type=DecisionType.Demand, action_scope={0: 1, 1: 1, 2: 30})\n", - "Action(from_station_idx=0, to_station_idx=2, number=0)\n" + "DecisionEvent {station_idx: 1, type: 'DecisionType.Demand', action_scope:{2: 0, 0: 0, 1: 29}}\n", + "Action {from_station_idx: 0, to_station_idx: '1', number:0}\n", + "*************\n", + "DecisionEvent {station_idx: 1, type: 'DecisionType.Demand', action_scope:{2: 0, 0: 0, 1: 29}}\n", + "Action {from_station_idx: 2, to_station_idx: '1', number:0}\n", + "*************\n", + "DecisionEvent {station_idx: 0, type: 'DecisionType.Demand', action_scope:{2: 1, 1: 0, 0: 30}}\n", + "Action {from_station_idx: 2, to_station_idx: '0', number:0}\n" ] } ], @@ -316,11 +325,16 @@ " target_idx_dock_tuple_list = [\n", " (k, v) for k, v in decision_event.action_scope.items() if k != decision_event.station_idx\n", " ]\n", - " # Randomly choose a target station weighted by the quantity of empty docks\n", - " target_idx, target_dock = random.choices(\n", - " target_idx_dock_tuple_list,\n", - " weights=[item[1] for item in target_idx_dock_tuple_list]\n", - " )[0]\n", + " weights=[item[1] for item in target_idx_dock_tuple_list]\n", + " if sum(weights) == 0:\n", + " target_idx = random.choices(target_idx_dock_tuple_list)[0][0]\n", + " target_dock = 0\n", + " else:\n", + " # Randomly choose a target station weighted by the quantity of empty docks\n", + " target_idx, target_dock = random.choices(\n", + " target_idx_dock_tuple_list,\n", + " weights=weights\n", + " )[0]\n", " # Generate the corresponding random Action\n", " action = Action(\n", " from_station_idx=decision_event.station_idx,\n", @@ -335,11 +349,16 @@ " target_idx_inventory_tuple_list = [\n", " (k, v) for k, v in decision_event.action_scope.items() if k != decision_event.station_idx\n", " ]\n", - " # Randomly choose a target station weighted by the bike inventory\n", - " target_idx, target_inventory = random.choices(\n", - " target_idx_inventory_tuple_list,\n", - " weights=[item[1] for item in target_idx_inventory_tuple_list]\n", - " )[0]\n", + " weights = [item[1] for item in target_idx_inventory_tuple_list]\n", + " if sum(weights) == 0:\n", + " target_idx = random.choices(target_idx_inventory_tuple_list)[0][0]\n", + " target_inventory = 0\n", + " else:\n", + " # Randomly choose a target station weighted by the bike inventory\n", + " target_idx, target_inventory = random.choices(\n", + " target_idx_inventory_tuple_list,\n", + " weights=weights\n", + " )[0]\n", " # Generate the corresponding random Action\n", " action = Action(\n", " from_station_idx=target_idx,\n", @@ -385,10 +404,6 @@ "name": "stdout", "output_type": "stream", "text": [ - "12:04:26 | WARNING | \u001b[33mBinary data files for scenario: citi_bike topology: toy.3s_4t not found.\u001b[0m\n", - "12:04:26 | WARNING | \u001b[33mGenerating temp binary data file for scenario: citi_bike topology: toy.3s_4t pid: 129013. If you want to keep the data, please use MARO CLI command 'maro env data generate -s citi_bike -t toy.3s_4t' to generate the binary data files first.\u001b[0m\n", - "12:04:26 | INFO | \u001b[32mGenerating trip data for topology toy.3s_4t .\u001b[0m\n", - "12:04:27 | INFO | \u001b[32mBuilding binary data from ~/.maro/data/citi_bike/.source/.clean/toy.3s_4t/278c7458875b4474/trips.csv to ~/.maro/data/citi_bike/.build/toy.3s_4t/278c7458875b4474/trips.bin\u001b[0m\n", "{'matrices': {'attributes': {...}, 'number': 1},\n", " 'stations': {'attributes': {...}, 'number': 3}}\n", "\n", @@ -427,18 +442,14 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "12:04:35 | WARNING | \u001b[33mBinary data files for scenario: citi_bike topology: toy.3s_4t not found.\u001b[0m\n", - "12:04:35 | WARNING | \u001b[33mGenerating temp binary data file for scenario: citi_bike topology: toy.3s_4t pid: 129013. If you want to keep the data, please use MARO CLI command 'maro env data generate -s citi_bike -t toy.3s_4t' to generate the binary data files first.\u001b[0m\n", - "12:04:35 | INFO | \u001b[32mGenerating trip data for topology toy.3s_4t .\u001b[0m\n", - "12:04:36 | INFO | \u001b[32mBuilding binary data from ~/.maro/data/citi_bike/.source/.clean/toy.3s_4t/80aa59d9c58d4b5e/trips.csv to ~/.maro/data/citi_bike/.build/toy.3s_4t/80aa59d9c58d4b5e/trips.bin\u001b[0m\n", - "array([11., 0., 11., 15., 0., 15., 16., 0., 16., 16., 0., 16.],\n", + "array([15., 0., 15., 16., 0., 16., 16., 0., 16., 18., 0., 18.],\n", " dtype=float32)\n" ] } @@ -496,7 +507,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.7.0" } }, "nbformat": 4, diff --git a/notebooks/container_inventory_management/interact_with_environment.ipynb b/notebooks/container_inventory_management/interact_with_environment.ipynb index 198f16db..ae3ea336 100644 --- a/notebooks/container_inventory_management/interact_with_environment.ipynb +++ b/notebooks/container_inventory_management/interact_with_environment.ipynb @@ -67,7 +67,7 @@ "output_type": "stream", "text": [ "'The available scenarios in MARO:'\n", - "['cim', 'citi_bike']\n", + "['cim', 'citi_bike', 'vm_scheduling']\n", "\n", "'The predefined topologies in CIM:'\n", "['global_trade.22p_l0.0',\n", @@ -147,7 +147,34 @@ "There will be 100 snapshots in total.\n", "\n", "Env Summary:\n", - "{'node_detail': {'matrices': {'attributes': {'full_on_ports': {'slots': 25,\n", + "{'event_payload': {'DISCHARGE_EMPTY': ['port_idx',\n", + " 'vessel_idx',\n", + " 'action_type',\n", + " 'quantity'],\n", + " 'DISCHARGE_FULL': ['vessel_idx',\n", + " 'port_idx',\n", + " 'from_port_idx',\n", + " 'quantity'],\n", + " 'LOAD_EMPTY': ['port_idx',\n", + " 'vessel_idx',\n", + " 'action_type',\n", + " 'quantity'],\n", + " 'LOAD_FULL': ['port_idx', 'vessel_idx'],\n", + " 'ORDER': ['tick',\n", + " 'src_port_idx',\n", + " 'dest_port_idx',\n", + " 'quantity'],\n", + " 'PENDING_DECISION': ['tick',\n", + " 'port_idx',\n", + " 'vessel_idx',\n", + " 'snapshot_list',\n", + " 'action_scope',\n", + " 'early_discharge'],\n", + " 'RETURN_EMPTY': ['port_idx', 'quantity'],\n", + " 'RETURN_FULL': ['src_port_idx', 'dest_port_idx', 'quantity'],\n", + " 'VESSEL_ARRIVAL': ['port_idx', 'vessel_idx'],\n", + " 'VESSEL_DEPARTURE': ['port_idx', 'vessel_idx']},\n", + " 'node_detail': {'matrices': {'attributes': {'full_on_ports': {'slots': 25,\n", " 'type': 'i'},\n", " 'full_on_vessels': {'slots': 30,\n", " 'type': 'i'},\n", @@ -184,8 +211,12 @@ " 'type': 'i'},\n", " 'future_stop_tick_list': {'slots': 3,\n", " 'type': 'i'},\n", + " 'is_parking': {'slots': 1,\n", + " 'type': 'i2'},\n", " 'last_loc_idx': {'slots': 1,\n", " 'type': 'i'},\n", + " 'loc_port_idx': {'slots': 1,\n", + " 'type': 'i'},\n", " 'next_loc_idx': {'slots': 1,\n", " 'type': 'i'},\n", " 'past_stop_list': {'slots': 4,\n", @@ -279,9 +310,8 @@ "- A valid `Action` instance, including:\n", " - **vessel_idx**: (int) The id of the vessel/operation object of the port/agent;\n", " - **port_idx**: (int) The id of the port/agent that take this action;\n", - " - **quantity**: (int) The sign of this value denotes different meanings:\n", - " - Positive quantity means unloading empty containers from vessel to port;\n", - " - Negative quantity means loading empty containers from port to vessel.\n", + " - **action_type**: (ActionType) Whether to load or discharge empty containers in this action;\n", + " - **quantity**: (int) The quantity of empty containers to be loaded/discharged.\n", "\n", "## Generate random actions based on the DecisionEvent\n", "\n", @@ -298,19 +328,32 @@ "output_type": "stream", "text": [ "*************\n", - "DecisionEvent(tick=14, port_idx=0, vessel_idx=5, action_scope=ActionScope(load=8856, discharge=1981))\n", - "Action(port_idx=0, vessel_idx=5, quantity=-2667)\n", + "DecisionEvent {port_idx: 4, vessel_idx: 5, action_scope: ActionScope {load: 6599, discharge: 0}, early_discharge: 0}\n", + "Action {action_type: 'ActionType.LOAD', port_idx: 4, vessel_idx: 5, quantity: 1960}\n", "*************\n", - "DecisionEvent(tick=21, port_idx=2, vessel_idx=1, action_scope=ActionScope(load=15997, discharge=3061))\n", - "Action(port_idx=2, vessel_idx=1, quantity=-11608)\n" + "DecisionEvent {port_idx: 1, vessel_idx: 3, action_scope: ActionScope {load: 0, discharge: 6027}, early_discharge: 0}\n", + "Action {action_type: 'ActionType.DISCHARGE', port_idx: 1, vessel_idx: 3, quantity: 3396}\n", + "*************\n", + "DecisionEvent {port_idx: 3, vessel_idx: 2, action_scope: ActionScope {load: 4730, discharge: 14383}, early_discharge: 0}\n", + "Action {action_type: 'ActionType.DISCHARGE', port_idx: 3, vessel_idx: 2, quantity: 10070}\n", + "*************\n", + "DecisionEvent {port_idx: 0, vessel_idx: 3, action_scope: ActionScope {load: 0, discharge: 2205}, early_discharge: 0}\n", + "Action {action_type: 'ActionType.LOAD', port_idx: 0, vessel_idx: 3, quantity: 0}\n", + "*************\n", + "DecisionEvent {port_idx: 4, vessel_idx: 1, action_scope: ActionScope {load: 0, discharge: 14495}, early_discharge: 0}\n", + "Action {action_type: 'ActionType.DISCHARGE', port_idx: 4, vessel_idx: 1, quantity: 8300}\n", + "*************\n", + "DecisionEvent {port_idx: 4, vessel_idx: 3, action_scope: ActionScope {load: 13824, discharge: 2205}, early_discharge: 0}\n", + "Action {action_type: 'ActionType.DISCHARGE', port_idx: 4, vessel_idx: 3, quantity: 841}\n" ] } ], "source": [ "from maro.simulator import Env\n", - "from maro.simulator.scenarios.cim.common import Action, DecisionEvent\n", + "from maro.simulator.scenarios.cim.common import Action, ActionType, DecisionEvent\n", "\n", "import random\n", + "from random import randint\n", "\n", "# Initialize an Env for cim scenario\n", "env = Env(scenario=\"cim\", topology=\"toy.5p_ssddd_l0.0\", start_tick=0, durations=100)\n", @@ -325,20 +368,20 @@ "\n", "while not is_done:\n", " # Generate a random Action according to the action_scope in DecisionEvent\n", - " random_quantity = random.randint(\n", - " -decision_event.action_scope.load,\n", - " decision_event.action_scope.discharge\n", - " )\n", + " action_scope = decision_event.action_scope\n", + " to_discharge = action_scope.discharge > 0 and randint(0, 1) > 0\n", + "\n", " action = Action(\n", - " vessel_idx=decision_event.vessel_idx,\n", - " port_idx=decision_event.port_idx,\n", - " quantity=random_quantity\n", + " decision_event.vessel_idx,\n", + " decision_event.port_idx,\n", + " randint(0, action_scope.discharge if to_discharge else action_scope.load),\n", + " ActionType.DISCHARGE if to_discharge else ActionType.LOAD\n", " )\n", - " \n", + "\n", " # Randomly sample some records to show in the output\n", " if random.random() > 0.95:\n", " print(f\"*************\\n{decision_event}\\n{action}\")\n", - " \n", + "\n", " # Respond the environment with the generated Action\n", " metrics, decision_event, is_done = env.step(action)" ] @@ -458,10 +501,13 @@ } ], "metadata": { + "interpreter": { + "hash": "767d51c1340bd893661ea55ea3124f6de3c7a262a8b4abca0554b478b1e2ff90" + }, "kernelspec": { - "display_name": "Python 3.7.7 64-bit", + "display_name": "Python 3", "language": "python", - "name": "python37764bita867a8fada044a15b631200655c7181c" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -473,7 +519,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.7" + "version": "3.7.0" } }, "nbformat": 4, diff --git a/playground.md b/playground.md index 6cf1cba2..3cb93b86 100644 --- a/playground.md +++ b/playground.md @@ -1,18 +1,21 @@ # Playground -Playground provides a standalone MARO running environment, it also includes examples of some predefined scenarios and quick-start tutorial. -## Main service in playground +The playground provides a standalone MARO environment along with several predefined scenario examples and quick-start tutorials. + +## Main service in the playground + | Service | Description | Host | |-------------------|------------------------------------------------------------|----------------------------| | `Redis Commander` | Redis Web GUI. | http://127.0.0.1:40009 | -| `Read the Docs` | Local host docs. | http://127.0.0.1:40010 | -| `Jupyter Lab` | Jupyter lab with MARO environment, examples, notebooks. | http://127.0.0.1:40011 | -*(Remember change ports, if you used different ports mapping.)* +| `Jupyter Lab` | Jupyter lab with MARO environment, examples, notebooks. | http://127.0.0.1:40010 | -## Major materials in root folder +*(Remember to change ports if you use different ports mapping.)* + +## Major materials in the root folder | Folder | Description | |-------------------|--------------------------------------------| | `examples` | Showcases of predefined scenarios. | | `notebooks` | Quick-start tutorial. | -*(Others can be ignored, which aren't mentioned in the table.)* \ No newline at end of file + +*(The ones not mentioned in this table can be ignored.)* diff --git a/scripts/build_playground.bat b/scripts/build_playground.bat index 6d2605c8..7468fce4 100644 --- a/scripts/build_playground.bat +++ b/scripts/build_playground.bat @@ -1,8 +1,8 @@ - -rem script to build docker for playground image on Windows, this require the source code of maro - -chdir "%~dp0.." - -call .\scripts\compile_cython.bat - -docker build -f ./docker_files/cpu.play.df . -t maro/playground:cpu \ No newline at end of file + +rem script to build docker for playground image on Windows, this require the source code of maro + +chdir "%~dp0.." + +call .\scripts\compile_cython.bat + +docker build -f ./docker_files/cpu.playground.df . -t maro2020/playground diff --git a/scripts/build_playground.sh b/scripts/build_playground.sh index a8be8698..446c39cc 100644 --- a/scripts/build_playground.sh +++ b/scripts/build_playground.sh @@ -10,4 +10,4 @@ fi bash ./scripts/compile_cython.sh -docker build -f ./docker_files/cpu.play.df . -t maro/playground:cpu \ No newline at end of file +docker build -f ./docker_files/cpu.playground.df . -t maro2020/playground diff --git a/scripts/install_maro.sh b/scripts/install_maro.sh index d9ea10b6..a77d0811 100644 --- a/scripts/install_maro.sh +++ b/scripts/install_maro.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Script to install maro in editable mode on linux/darwin, +# Script to install maro in editable mode on linux/darwin, # usually for development. if [[ "$OSTYPE" == "linux-gnu"* ]]; then @@ -16,4 +16,4 @@ pip install -r ./maro/requirements.build.txt bash scripts/compile_cython.sh # Install MARO in editable mode. -pip install -e . \ No newline at end of file +pip install -e . diff --git a/scripts/run_playground.sh b/scripts/run_playground.sh index 21754589..812435ce 100644 --- a/scripts/run_playground.sh +++ b/scripts/run_playground.sh @@ -5,8 +5,5 @@ ./redis-6.0.6/src/redis-server --port 6379 & redis-commander --port 40009 & -# Python 3.6 -cd ./docs/_build/html; python -m http.server 40010 -b 0.0.0.0 & - # It's only for your play locally or in an internal network environment, so disable the token for convenience -cd ../../..; jupyter lab --port 40011 --allow-root --ip 0.0.0.0 --NotebookApp.token='' \ No newline at end of file +jupyter lab --port 40010 --allow-root --ip 0.0.0.0 --NotebookApp.token='' diff --git a/setup.py b/setup.py index c8e5c5c2..1065bb56 100644 --- a/setup.py +++ b/setup.py @@ -87,8 +87,8 @@ setup( description="MARO Python Package", long_description=readme, long_description_content_type="text/x-rst", - author="Arthur Jiang", - author_email="shujia.jiang@microsoft.com", + author="MARO Team", + author_email="maro-team@microsoft.com", url="https://github.com/microsoft/maro", project_urls={ "Code": "https://github.com/microsoft/maro",